From df46b9a44ceb5af2ea2351ce8e28ae7bd840b00f Mon Sep 17 00:00:00 2001 From: Mike Christie Date: Mon, 20 Jun 2005 14:04:44 +0200 Subject: [PATCH 001/114] [PATCH] Add blk_rq_map_kern() Add blk_rq_map_kern which takes a kernel buffer and maps it into a request and bio. This can be used by the dm hw_handlers, old sg_scsi_ioctl, and one day scsi special requests so all requests comming into scsi will have bios. All requests having bios should allow scsi to use scatter lists for all IO and allow it to use block layer functions. Signed-off-by: Jens Axboe --- drivers/block/ll_rw_blk.c | 56 +++++++++++++++++++++++++++++++++ fs/bio.c | 66 +++++++++++++++++++++++++++++++++++++++ include/linux/bio.h | 2 ++ include/linux/blkdev.h | 2 ++ 4 files changed, 126 insertions(+) diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index f20eba22b14b..e30a3c93b70c 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -281,6 +281,7 @@ static inline void rq_init(request_queue_t *q, struct request *rq) rq->special = NULL; rq->data_len = 0; rq->data = NULL; + rq->nr_phys_segments = 0; rq->sense = NULL; rq->end_io = NULL; rq->end_io_data = NULL; @@ -2176,6 +2177,61 @@ int blk_rq_unmap_user(struct request *rq, struct bio *bio, unsigned int ulen) EXPORT_SYMBOL(blk_rq_unmap_user); +static int blk_rq_map_kern_endio(struct bio *bio, unsigned int bytes_done, + int error) +{ + if (bio->bi_size) + return 1; + + bio_put(bio); + return 0; +} + +/** + * blk_rq_map_kern - map kernel data to a request, for REQ_BLOCK_PC usage + * @q: request queue where request should be inserted + * @rw: READ or WRITE data + * @kbuf: the kernel buffer + * @len: length of user data + */ +struct request *blk_rq_map_kern(request_queue_t *q, int rw, void *kbuf, + unsigned int len, unsigned int gfp_mask) +{ + struct request *rq; + struct bio *bio; + + if (len > (q->max_sectors << 9)) + return ERR_PTR(-EINVAL); + if ((!len && kbuf) || (len && !kbuf)) + return ERR_PTR(-EINVAL); + + rq = blk_get_request(q, rw, gfp_mask); + if (!rq) + return ERR_PTR(-ENOMEM); + + bio = bio_map_kern(q, kbuf, len, gfp_mask); + if (!IS_ERR(bio)) { + if (rw) + bio->bi_rw |= (1 << BIO_RW); + bio->bi_end_io = blk_rq_map_kern_endio; + + rq->bio = rq->biotail = bio; + blk_rq_bio_prep(q, rq, bio); + + rq->buffer = rq->data = NULL; + rq->data_len = len; + return rq; + } + + /* + * bio is the err-ptr + */ + blk_put_request(rq); + return (struct request *) bio; +} + +EXPORT_SYMBOL(blk_rq_map_kern); + /** * blk_execute_rq - insert a request into queue for execution * @q: queue to insert the request in diff --git a/fs/bio.c b/fs/bio.c index 3a1472acc361..707b9af2dd01 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -701,6 +701,71 @@ void bio_unmap_user(struct bio *bio) bio_put(bio); } +static struct bio *__bio_map_kern(request_queue_t *q, void *data, + unsigned int len, unsigned int gfp_mask) +{ + unsigned long kaddr = (unsigned long)data; + unsigned long end = (kaddr + len + PAGE_SIZE - 1) >> PAGE_SHIFT; + unsigned long start = kaddr >> PAGE_SHIFT; + const int nr_pages = end - start; + int offset, i; + struct bio *bio; + + bio = bio_alloc(gfp_mask, nr_pages); + if (!bio) + return ERR_PTR(-ENOMEM); + + offset = offset_in_page(kaddr); + for (i = 0; i < nr_pages; i++) { + unsigned int bytes = PAGE_SIZE - offset; + + if (len <= 0) + break; + + if (bytes > len) + bytes = len; + + if (__bio_add_page(q, bio, virt_to_page(data), bytes, + offset) < bytes) + break; + + data += bytes; + len -= bytes; + offset = 0; + } + + return bio; +} + +/** + * bio_map_kern - map kernel address into bio + * @q: the request_queue_t for the bio + * @data: pointer to buffer to map + * @len: length in bytes + * @gfp_mask: allocation flags for bio allocation + * + * Map the kernel address into a bio suitable for io to a block + * device. Returns an error pointer in case of error. + */ +struct bio *bio_map_kern(request_queue_t *q, void *data, unsigned int len, + unsigned int gfp_mask) +{ + struct bio *bio; + + bio = __bio_map_kern(q, data, len, gfp_mask); + if (IS_ERR(bio)) + return bio; + + if (bio->bi_size == len) + return bio; + + /* + * Don't support partial mappings. + */ + bio_put(bio); + return ERR_PTR(-EINVAL); +} + /* * bio_set_pages_dirty() and bio_check_pages_dirty() are support functions * for performing direct-IO in BIOs. @@ -1088,6 +1153,7 @@ EXPORT_SYMBOL(bio_add_page); EXPORT_SYMBOL(bio_get_nr_vecs); EXPORT_SYMBOL(bio_map_user); EXPORT_SYMBOL(bio_unmap_user); +EXPORT_SYMBOL(bio_map_kern); EXPORT_SYMBOL(bio_pair_release); EXPORT_SYMBOL(bio_split); EXPORT_SYMBOL(bio_split_pool); diff --git a/include/linux/bio.h b/include/linux/bio.h index 038022763f09..1dd2bc2e84ae 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -282,6 +282,8 @@ extern int bio_get_nr_vecs(struct block_device *); extern struct bio *bio_map_user(struct request_queue *, struct block_device *, unsigned long, unsigned int, int); extern void bio_unmap_user(struct bio *); +extern struct bio *bio_map_kern(struct request_queue *, void *, unsigned int, + unsigned int); extern void bio_set_pages_dirty(struct bio *bio); extern void bio_check_pages_dirty(struct bio *bio); extern struct bio *bio_copy_user(struct request_queue *, unsigned long, unsigned int, int); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 4a99b76c5a33..67339bc5f6bc 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -560,6 +560,8 @@ extern void blk_run_queue(request_queue_t *); extern void blk_queue_activity_fn(request_queue_t *, activity_fn *, void *); extern struct request *blk_rq_map_user(request_queue_t *, int, void __user *, unsigned int); extern int blk_rq_unmap_user(struct request *, struct bio *, unsigned int); +extern struct request *blk_rq_map_kern(request_queue_t *, int, void *, + unsigned int, unsigned int); extern int blk_execute_rq(request_queue_t *, struct gendisk *, struct request *); static inline request_queue_t *bdev_get_queue(struct block_device *bdev) From b823825e8e09aac6dc1ca362cd5639a87329d636 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Mon, 20 Jun 2005 14:05:27 +0200 Subject: [PATCH 002/114] [PATCH] Keep the bio end_io parts inside of bio.c for blk_rq_map_kern() Signed-off-by: Jens Axboe --- drivers/block/ll_rw_blk.c | 11 ----------- fs/bio.c | 11 +++++++++++ 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index e30a3c93b70c..1471aca6fa18 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -2177,16 +2177,6 @@ int blk_rq_unmap_user(struct request *rq, struct bio *bio, unsigned int ulen) EXPORT_SYMBOL(blk_rq_unmap_user); -static int blk_rq_map_kern_endio(struct bio *bio, unsigned int bytes_done, - int error) -{ - if (bio->bi_size) - return 1; - - bio_put(bio); - return 0; -} - /** * blk_rq_map_kern - map kernel data to a request, for REQ_BLOCK_PC usage * @q: request queue where request should be inserted @@ -2213,7 +2203,6 @@ struct request *blk_rq_map_kern(request_queue_t *q, int rw, void *kbuf, if (!IS_ERR(bio)) { if (rw) bio->bi_rw |= (1 << BIO_RW); - bio->bi_end_io = blk_rq_map_kern_endio; rq->bio = rq->biotail = bio; blk_rq_bio_prep(q, rq, bio); diff --git a/fs/bio.c b/fs/bio.c index 707b9af2dd01..c0d9140e470c 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -701,6 +701,16 @@ void bio_unmap_user(struct bio *bio) bio_put(bio); } +static int bio_map_kern_endio(struct bio *bio, unsigned int bytes_done, int err) +{ + if (bio->bi_size) + return 1; + + bio_put(bio); + return 0; +} + + static struct bio *__bio_map_kern(request_queue_t *q, void *data, unsigned int len, unsigned int gfp_mask) { @@ -734,6 +744,7 @@ static struct bio *__bio_map_kern(request_queue_t *q, void *data, offset = 0; } + bio->bi_end_io = bio_map_kern_endio; return bio; } From dd1cab95f356f1395278633565f198463cf6bd24 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Mon, 20 Jun 2005 14:06:01 +0200 Subject: [PATCH 003/114] [PATCH] Cleanup blk_rq_map_* interfaces Change the blk_rq_map_user() and blk_rq_map_kern() interface to require a previously allocated request to be passed in. This is both more efficient for multiple iterations of mapping data to the same request, and it is also a much nicer API. Signed-off-by: Jens Axboe --- drivers/block/ll_rw_blk.c | 68 +++++++++++++++----------------------- drivers/block/scsi_ioctl.c | 23 ++++++++----- drivers/cdrom/cdrom.c | 13 +++++--- include/linux/blkdev.h | 7 ++-- 4 files changed, 53 insertions(+), 58 deletions(-) diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 1471aca6fa18..42c4f3651cf8 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -2107,21 +2107,19 @@ EXPORT_SYMBOL(blk_insert_request); * original bio must be passed back in to blk_rq_unmap_user() for proper * unmapping. */ -struct request *blk_rq_map_user(request_queue_t *q, int rw, void __user *ubuf, - unsigned int len) +int blk_rq_map_user(request_queue_t *q, struct request *rq, void __user *ubuf, + unsigned int len) { unsigned long uaddr; - struct request *rq; struct bio *bio; + int reading; if (len > (q->max_sectors << 9)) - return ERR_PTR(-EINVAL); - if ((!len && ubuf) || (len && !ubuf)) - return ERR_PTR(-EINVAL); + return -EINVAL; + if (!len || !ubuf) + return -EINVAL; - rq = blk_get_request(q, rw, __GFP_WAIT); - if (!rq) - return ERR_PTR(-ENOMEM); + reading = rq_data_dir(rq) == READ; /* * if alignment requirement is satisfied, map in user pages for @@ -2129,9 +2127,9 @@ struct request *blk_rq_map_user(request_queue_t *q, int rw, void __user *ubuf, */ uaddr = (unsigned long) ubuf; if (!(uaddr & queue_dma_alignment(q)) && !(len & queue_dma_alignment(q))) - bio = bio_map_user(q, NULL, uaddr, len, rw == READ); + bio = bio_map_user(q, NULL, uaddr, len, reading); else - bio = bio_copy_user(q, uaddr, len, rw == READ); + bio = bio_copy_user(q, uaddr, len, reading); if (!IS_ERR(bio)) { rq->bio = rq->biotail = bio; @@ -2139,14 +2137,13 @@ struct request *blk_rq_map_user(request_queue_t *q, int rw, void __user *ubuf, rq->buffer = rq->data = NULL; rq->data_len = len; - return rq; + return 0; } /* * bio is the err-ptr */ - blk_put_request(rq); - return (struct request *) bio; + return PTR_ERR(bio); } EXPORT_SYMBOL(blk_rq_map_user); @@ -2160,7 +2157,7 @@ EXPORT_SYMBOL(blk_rq_map_user); * Description: * Unmap a request previously mapped by blk_rq_map_user(). */ -int blk_rq_unmap_user(struct request *rq, struct bio *bio, unsigned int ulen) +int blk_rq_unmap_user(struct bio *bio, unsigned int ulen) { int ret = 0; @@ -2171,8 +2168,7 @@ int blk_rq_unmap_user(struct request *rq, struct bio *bio, unsigned int ulen) ret = bio_uncopy_user(bio); } - blk_put_request(rq); - return ret; + return 0; } EXPORT_SYMBOL(blk_rq_unmap_user); @@ -2184,39 +2180,29 @@ EXPORT_SYMBOL(blk_rq_unmap_user); * @kbuf: the kernel buffer * @len: length of user data */ -struct request *blk_rq_map_kern(request_queue_t *q, int rw, void *kbuf, - unsigned int len, unsigned int gfp_mask) +int blk_rq_map_kern(request_queue_t *q, struct request *rq, void *kbuf, + unsigned int len, unsigned int gfp_mask) { - struct request *rq; struct bio *bio; if (len > (q->max_sectors << 9)) - return ERR_PTR(-EINVAL); - if ((!len && kbuf) || (len && !kbuf)) - return ERR_PTR(-EINVAL); - - rq = blk_get_request(q, rw, gfp_mask); - if (!rq) - return ERR_PTR(-ENOMEM); + return -EINVAL; + if (!len || !kbuf) + return -EINVAL; bio = bio_map_kern(q, kbuf, len, gfp_mask); - if (!IS_ERR(bio)) { - if (rw) - bio->bi_rw |= (1 << BIO_RW); + if (IS_ERR(bio)) + return PTR_ERR(bio); - rq->bio = rq->biotail = bio; - blk_rq_bio_prep(q, rq, bio); + if (rq_data_dir(rq) == WRITE) + bio->bi_rw |= (1 << BIO_RW); - rq->buffer = rq->data = NULL; - rq->data_len = len; - return rq; - } + rq->bio = rq->biotail = bio; + blk_rq_bio_prep(q, rq, bio); - /* - * bio is the err-ptr - */ - blk_put_request(rq); - return (struct request *) bio; + rq->buffer = rq->data = NULL; + rq->data_len = len; + return 0; } EXPORT_SYMBOL(blk_rq_map_kern); diff --git a/drivers/block/scsi_ioctl.c b/drivers/block/scsi_ioctl.c index 681871ca5d60..93c4ca874be3 100644 --- a/drivers/block/scsi_ioctl.c +++ b/drivers/block/scsi_ioctl.c @@ -216,7 +216,7 @@ static int sg_io(struct file *file, request_queue_t *q, struct gendisk *bd_disk, struct sg_io_hdr *hdr) { unsigned long start_time; - int reading, writing; + int reading, writing, ret; struct request *rq; struct bio *bio; char sense[SCSI_SENSE_BUFFERSIZE]; @@ -255,14 +255,17 @@ static int sg_io(struct file *file, request_queue_t *q, reading = 1; break; } + } - rq = blk_rq_map_user(q, writing ? WRITE : READ, hdr->dxferp, - hdr->dxfer_len); + rq = blk_get_request(q, writing ? WRITE : READ, GFP_KERNEL); + if (!rq) + return -ENOMEM; - if (IS_ERR(rq)) - return PTR_ERR(rq); - } else - rq = blk_get_request(q, READ, __GFP_WAIT); + if (reading || writing) { + ret = blk_rq_map_user(q, rq, hdr->dxferp, hdr->dxfer_len); + if (ret) + goto out; + } /* * fill in request structure @@ -321,11 +324,13 @@ static int sg_io(struct file *file, request_queue_t *q, } if (blk_rq_unmap_user(rq, bio, hdr->dxfer_len)) - return -EFAULT; + ret = -EFAULT; /* may not have succeeded, but output values written to control * structure (struct sg_io_hdr). */ - return 0; +out: + blk_put_request(rq); + return ret; } #define OMAX_SB_LEN 16 /* For backward compatibility */ diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index beaa561f2ed8..6a7d926774a1 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -2097,6 +2097,10 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf, if (!q) return -ENXIO; + rq = blk_get_request(q, READ, GFP_KERNEL); + if (!rq) + return -ENOMEM; + cdi->last_sense = 0; while (nframes) { @@ -2108,9 +2112,9 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf, len = nr * CD_FRAMESIZE_RAW; - rq = blk_rq_map_user(q, READ, ubuf, len); - if (IS_ERR(rq)) - return PTR_ERR(rq); + ret = blk_rq_map_user(q, rq, ubuf, len); + if (ret) + break; memset(rq->cmd, 0, sizeof(rq->cmd)); rq->cmd[0] = GPCMD_READ_CD; @@ -2138,7 +2142,7 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf, cdi->last_sense = s->sense_key; } - if (blk_rq_unmap_user(rq, bio, len)) + if (blk_rq_unmap_user(bio, len)) ret = -EFAULT; if (ret) @@ -2149,6 +2153,7 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf, ubuf += len; } + blk_put_request(rq); return ret; } diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 67339bc5f6bc..fc0dce078616 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -558,10 +558,9 @@ extern void blk_sync_queue(struct request_queue *q); extern void __blk_stop_queue(request_queue_t *q); extern void blk_run_queue(request_queue_t *); extern void blk_queue_activity_fn(request_queue_t *, activity_fn *, void *); -extern struct request *blk_rq_map_user(request_queue_t *, int, void __user *, unsigned int); -extern int blk_rq_unmap_user(struct request *, struct bio *, unsigned int); -extern struct request *blk_rq_map_kern(request_queue_t *, int, void *, - unsigned int, unsigned int); +extern int blk_rq_map_user(request_queue_t *, struct request *, void __user *, unsigned int); +extern int blk_rq_unmap_user(struct bio *, unsigned int); +extern int blk_rq_map_kern(request_queue_t *, struct request *, void *, unsigned int, unsigned int); extern int blk_execute_rq(request_queue_t *, struct gendisk *, struct request *); static inline request_queue_t *bdev_get_queue(struct block_device *bdev) From f1970baf6d74e03bd32072ab453f2fc01bc1b8d3 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Mon, 20 Jun 2005 14:06:52 +0200 Subject: [PATCH 004/114] [PATCH] Add scatter-gather support for the block layer SG_IO Signed-off-by: Jens Axboe --- drivers/block/ll_rw_blk.c | 64 +++++++++++++++-- drivers/block/scsi_ioctl.c | 34 ++++++--- fs/bio.c | 142 ++++++++++++++++++++++++++----------- include/linux/bio.h | 4 ++ include/linux/blkdev.h | 1 + 5 files changed, 187 insertions(+), 58 deletions(-) diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 42c4f3651cf8..874e46fc3748 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -2148,6 +2148,50 @@ int blk_rq_map_user(request_queue_t *q, struct request *rq, void __user *ubuf, EXPORT_SYMBOL(blk_rq_map_user); +/** + * blk_rq_map_user_iov - map user data to a request, for REQ_BLOCK_PC usage + * @q: request queue where request should be inserted + * @rq: request to map data to + * @iov: pointer to the iovec + * @iov_count: number of elements in the iovec + * + * Description: + * Data will be mapped directly for zero copy io, if possible. Otherwise + * a kernel bounce buffer is used. + * + * A matching blk_rq_unmap_user() must be issued at the end of io, while + * still in process context. + * + * Note: The mapped bio may need to be bounced through blk_queue_bounce() + * before being submitted to the device, as pages mapped may be out of + * reach. It's the callers responsibility to make sure this happens. The + * original bio must be passed back in to blk_rq_unmap_user() for proper + * unmapping. + */ +int blk_rq_map_user_iov(request_queue_t *q, struct request *rq, + struct sg_iovec *iov, int iov_count) +{ + struct bio *bio; + + if (!iov || iov_count <= 0) + return -EINVAL; + + /* we don't allow misaligned data like bio_map_user() does. If the + * user is using sg, they're expected to know the alignment constraints + * and respect them accordingly */ + bio = bio_map_user_iov(q, NULL, iov, iov_count, rq_data_dir(rq)== READ); + if (IS_ERR(bio)) + return PTR_ERR(bio); + + rq->bio = rq->biotail = bio; + blk_rq_bio_prep(q, rq, bio); + rq->buffer = rq->data = NULL; + rq->data_len = bio->bi_size; + return 0; +} + +EXPORT_SYMBOL(blk_rq_map_user_iov); + /** * blk_rq_unmap_user - unmap a request with user data * @rq: request to be unmapped @@ -2207,6 +2251,19 @@ int blk_rq_map_kern(request_queue_t *q, struct request *rq, void *kbuf, EXPORT_SYMBOL(blk_rq_map_kern); +void blk_execute_rq_nowait(request_queue_t *q, struct gendisk *bd_disk, + struct request *rq, int at_head, + void (*done)(struct request *)) +{ + int where = at_head ? ELEVATOR_INSERT_FRONT : ELEVATOR_INSERT_BACK; + + rq->rq_disk = bd_disk; + rq->flags |= REQ_NOMERGE; + rq->end_io = done; + elv_add_request(q, rq, where, 1); + generic_unplug_device(q); +} + /** * blk_execute_rq - insert a request into queue for execution * @q: queue to insert the request in @@ -2224,8 +2281,6 @@ int blk_execute_rq(request_queue_t *q, struct gendisk *bd_disk, char sense[SCSI_SENSE_BUFFERSIZE]; int err = 0; - rq->rq_disk = bd_disk; - /* * we need an extra reference to the request, so we can look at * it after io completion @@ -2238,11 +2293,8 @@ int blk_execute_rq(request_queue_t *q, struct gendisk *bd_disk, rq->sense_len = 0; } - rq->flags |= REQ_NOMERGE; rq->waiting = &wait; - rq->end_io = blk_end_sync_rq; - elv_add_request(q, rq, ELEVATOR_INSERT_BACK, 1); - generic_unplug_device(q); + blk_execute_rq_nowait(q, bd_disk, rq, 0, blk_end_sync_rq); wait_for_completion(&wait); rq->waiting = NULL; diff --git a/drivers/block/scsi_ioctl.c b/drivers/block/scsi_ioctl.c index 93c4ca874be3..09a7e73a0812 100644 --- a/drivers/block/scsi_ioctl.c +++ b/drivers/block/scsi_ioctl.c @@ -231,17 +231,11 @@ static int sg_io(struct file *file, request_queue_t *q, if (verify_command(file, cmd)) return -EPERM; - /* - * we'll do that later - */ - if (hdr->iovec_count) - return -EOPNOTSUPP; - if (hdr->dxfer_len > (q->max_sectors << 9)) return -EIO; reading = writing = 0; - if (hdr->dxfer_len) { + if (hdr->dxfer_len) switch (hdr->dxfer_direction) { default: return -EINVAL; @@ -261,11 +255,29 @@ static int sg_io(struct file *file, request_queue_t *q, if (!rq) return -ENOMEM; - if (reading || writing) { - ret = blk_rq_map_user(q, rq, hdr->dxferp, hdr->dxfer_len); - if (ret) + if (hdr->iovec_count) { + const int size = sizeof(struct sg_iovec) * hdr->iovec_count; + struct sg_iovec *iov; + + iov = kmalloc(size, GFP_KERNEL); + if (!iov) { + ret = -ENOMEM; goto out; - } + } + + if (copy_from_user(iov, hdr->dxferp, size)) { + kfree(iov); + ret = -EFAULT; + goto out; + } + + ret = blk_rq_map_user_iov(q, rq, iov, hdr->iovec_count); + kfree(iov); + } else if (hdr->dxfer_len) + ret = blk_rq_map_user(q, rq, hdr->dxferp, hdr->dxfer_len); + + if (ret) + goto out; /* * fill in request structure diff --git a/fs/bio.c b/fs/bio.c index c0d9140e470c..24e4045788e2 100644 --- a/fs/bio.c +++ b/fs/bio.c @@ -25,6 +25,7 @@ #include #include #include +#include /* for struct sg_iovec */ #define BIO_POOL_SIZE 256 @@ -549,22 +550,34 @@ struct bio *bio_copy_user(request_queue_t *q, unsigned long uaddr, return ERR_PTR(ret); } -static struct bio *__bio_map_user(request_queue_t *q, struct block_device *bdev, - unsigned long uaddr, unsigned int len, - int write_to_vm) +static struct bio *__bio_map_user_iov(request_queue_t *q, + struct block_device *bdev, + struct sg_iovec *iov, int iov_count, + int write_to_vm) { - unsigned long end = (uaddr + len + PAGE_SIZE - 1) >> PAGE_SHIFT; - unsigned long start = uaddr >> PAGE_SHIFT; - const int nr_pages = end - start; - int ret, offset, i; + int i, j; + int nr_pages = 0; struct page **pages; struct bio *bio; + int cur_page = 0; + int ret, offset; - /* - * transfer and buffer must be aligned to at least hardsector - * size for now, in the future we can relax this restriction - */ - if ((uaddr & queue_dma_alignment(q)) || (len & queue_dma_alignment(q))) + for (i = 0; i < iov_count; i++) { + unsigned long uaddr = (unsigned long)iov[i].iov_base; + unsigned long len = iov[i].iov_len; + unsigned long end = (uaddr + len + PAGE_SIZE - 1) >> PAGE_SHIFT; + unsigned long start = uaddr >> PAGE_SHIFT; + + nr_pages += end - start; + /* + * transfer and buffer must be aligned to at least hardsector + * size for now, in the future we can relax this restriction + */ + if ((uaddr & queue_dma_alignment(q)) || (len & queue_dma_alignment(q))) + return ERR_PTR(-EINVAL); + } + + if (!nr_pages) return ERR_PTR(-EINVAL); bio = bio_alloc(GFP_KERNEL, nr_pages); @@ -576,42 +589,54 @@ static struct bio *__bio_map_user(request_queue_t *q, struct block_device *bdev, if (!pages) goto out; - down_read(¤t->mm->mmap_sem); - ret = get_user_pages(current, current->mm, uaddr, nr_pages, - write_to_vm, 0, pages, NULL); - up_read(¤t->mm->mmap_sem); + memset(pages, 0, nr_pages * sizeof(struct page *)); - if (ret < nr_pages) - goto out; + for (i = 0; i < iov_count; i++) { + unsigned long uaddr = (unsigned long)iov[i].iov_base; + unsigned long len = iov[i].iov_len; + unsigned long end = (uaddr + len + PAGE_SIZE - 1) >> PAGE_SHIFT; + unsigned long start = uaddr >> PAGE_SHIFT; + const int local_nr_pages = end - start; + const int page_limit = cur_page + local_nr_pages; + + down_read(¤t->mm->mmap_sem); + ret = get_user_pages(current, current->mm, uaddr, + local_nr_pages, + write_to_vm, 0, &pages[cur_page], NULL); + up_read(¤t->mm->mmap_sem); - bio->bi_bdev = bdev; + if (ret < local_nr_pages) + goto out_unmap; - offset = uaddr & ~PAGE_MASK; - for (i = 0; i < nr_pages; i++) { - unsigned int bytes = PAGE_SIZE - offset; - if (len <= 0) - break; + offset = uaddr & ~PAGE_MASK; + for (j = cur_page; j < page_limit; j++) { + unsigned int bytes = PAGE_SIZE - offset; - if (bytes > len) - bytes = len; + if (len <= 0) + break; + + if (bytes > len) + bytes = len; + /* + * sorry... + */ + if (__bio_add_page(q, bio, pages[j], bytes, offset) < bytes) + break; + + len -= bytes; + offset = 0; + } + + cur_page = j; /* - * sorry... + * release the pages we didn't map into the bio, if any */ - if (__bio_add_page(q, bio, pages[i], bytes, offset) < bytes) - break; - - len -= bytes; - offset = 0; + while (j < page_limit) + page_cache_release(pages[j++]); } - /* - * release the pages we didn't map into the bio, if any - */ - while (i < nr_pages) - page_cache_release(pages[i++]); - kfree(pages); /* @@ -620,9 +645,17 @@ static struct bio *__bio_map_user(request_queue_t *q, struct block_device *bdev, if (!write_to_vm) bio->bi_rw |= (1 << BIO_RW); + bio->bi_bdev = bdev; bio->bi_flags |= (1 << BIO_USER_MAPPED); return bio; -out: + + out_unmap: + for (i = 0; i < nr_pages; i++) { + if(!pages[i]) + break; + page_cache_release(pages[i]); + } + out: kfree(pages); bio_put(bio); return ERR_PTR(ret); @@ -642,9 +675,33 @@ static struct bio *__bio_map_user(request_queue_t *q, struct block_device *bdev, struct bio *bio_map_user(request_queue_t *q, struct block_device *bdev, unsigned long uaddr, unsigned int len, int write_to_vm) { - struct bio *bio; + struct sg_iovec iov; - bio = __bio_map_user(q, bdev, uaddr, len, write_to_vm); + iov.iov_base = (__user void *)uaddr; + iov.iov_len = len; + + return bio_map_user_iov(q, bdev, &iov, 1, write_to_vm); +} + +/** + * bio_map_user_iov - map user sg_iovec table into bio + * @q: the request_queue_t for the bio + * @bdev: destination block device + * @iov: the iovec. + * @iov_count: number of elements in the iovec + * @write_to_vm: bool indicating writing to pages or not + * + * Map the user space address into a bio suitable for io to a block + * device. Returns an error pointer in case of error. + */ +struct bio *bio_map_user_iov(request_queue_t *q, struct block_device *bdev, + struct sg_iovec *iov, int iov_count, + int write_to_vm) +{ + struct bio *bio; + int len = 0, i; + + bio = __bio_map_user_iov(q, bdev, iov, iov_count, write_to_vm); if (IS_ERR(bio)) return bio; @@ -657,6 +714,9 @@ struct bio *bio_map_user(request_queue_t *q, struct block_device *bdev, */ bio_get(bio); + for (i = 0; i < iov_count; i++) + len += iov[i].iov_len; + if (bio->bi_size == len) return bio; diff --git a/include/linux/bio.h b/include/linux/bio.h index 1dd2bc2e84ae..ebcd03ba2e20 100644 --- a/include/linux/bio.h +++ b/include/linux/bio.h @@ -281,6 +281,10 @@ extern int bio_add_page(struct bio *, struct page *, unsigned int,unsigned int); extern int bio_get_nr_vecs(struct block_device *); extern struct bio *bio_map_user(struct request_queue *, struct block_device *, unsigned long, unsigned int, int); +struct sg_iovec; +extern struct bio *bio_map_user_iov(struct request_queue *, + struct block_device *, + struct sg_iovec *, int, int); extern void bio_unmap_user(struct bio *); extern struct bio *bio_map_kern(struct request_queue *, void *, unsigned int, unsigned int); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index fc0dce078616..0430ea3e5f2e 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -561,6 +561,7 @@ extern void blk_queue_activity_fn(request_queue_t *, activity_fn *, void *); extern int blk_rq_map_user(request_queue_t *, struct request *, void __user *, unsigned int); extern int blk_rq_unmap_user(struct bio *, unsigned int); extern int blk_rq_map_kern(request_queue_t *, struct request *, void *, unsigned int, unsigned int); +extern int blk_rq_map_user_iov(request_queue_t *, struct request *, struct sg_iovec *, int); extern int blk_execute_rq(request_queue_t *, struct gendisk *, struct request *); static inline request_queue_t *bdev_get_queue(struct block_device *bdev) From e1f546e185e9d8cb9303d74d1cd5bc704f265384 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Mon, 20 Jun 2005 14:07:17 +0200 Subject: [PATCH 005/114] [PATCH] The blk_rq_map_user() change missed an update in scsi_ioctl.c Signed-off-by: Jens Axboe --- drivers/block/scsi_ioctl.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/block/scsi_ioctl.c b/drivers/block/scsi_ioctl.c index 09a7e73a0812..b35cb75c7528 100644 --- a/drivers/block/scsi_ioctl.c +++ b/drivers/block/scsi_ioctl.c @@ -216,7 +216,7 @@ static int sg_io(struct file *file, request_queue_t *q, struct gendisk *bd_disk, struct sg_io_hdr *hdr) { unsigned long start_time; - int reading, writing, ret; + int reading, writing, ret = 0; struct request *rq; struct bio *bio; char sense[SCSI_SENSE_BUFFERSIZE]; @@ -249,7 +249,6 @@ static int sg_io(struct file *file, request_queue_t *q, reading = 1; break; } - } rq = blk_get_request(q, writing ? WRITE : READ, GFP_KERNEL); if (!rq) @@ -335,7 +334,7 @@ static int sg_io(struct file *file, request_queue_t *q, hdr->sb_len_wr = len; } - if (blk_rq_unmap_user(rq, bio, hdr->dxfer_len)) + if (blk_rq_unmap_user(bio, hdr->dxfer_len)) ret = -EFAULT; /* may not have succeeded, but output values written to control From f63eb21b4f32028755b6b9d47e5eb13c18ba0cae Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Mon, 20 Jun 2005 14:10:25 +0200 Subject: [PATCH 006/114] [PATCH] kill 'reading' variable in sg_io(), it isn't used anymore. Signed-off-by: Jens Axboe --- drivers/block/scsi_ioctl.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/block/scsi_ioctl.c b/drivers/block/scsi_ioctl.c index b35cb75c7528..7717b76f7f20 100644 --- a/drivers/block/scsi_ioctl.c +++ b/drivers/block/scsi_ioctl.c @@ -216,7 +216,7 @@ static int sg_io(struct file *file, request_queue_t *q, struct gendisk *bd_disk, struct sg_io_hdr *hdr) { unsigned long start_time; - int reading, writing, ret = 0; + int writing = 0, ret = 0; struct request *rq; struct bio *bio; char sense[SCSI_SENSE_BUFFERSIZE]; @@ -234,19 +234,15 @@ static int sg_io(struct file *file, request_queue_t *q, if (hdr->dxfer_len > (q->max_sectors << 9)) return -EIO; - reading = writing = 0; if (hdr->dxfer_len) switch (hdr->dxfer_direction) { default: return -EINVAL; case SG_DXFER_TO_FROM_DEV: - reading = 1; - /* fall through */ case SG_DXFER_TO_DEV: writing = 1; break; case SG_DXFER_FROM_DEV: - reading = 1; break; } From 994ca9a19616f0d4161a9e825f0835925d522426 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Mon, 20 Jun 2005 14:11:09 +0200 Subject: [PATCH 007/114] [PATCH] update blk_execute_rq to take an at_head parameter Original From: Mike Christie Modified to split out block changes (this patch) and SCSI pieces. Signed-off-by: Jens Axboe Signed-off-by: James Bottomley --- drivers/block/ll_rw_blk.c | 7 ++++--- drivers/block/scsi_ioctl.c | 6 +++--- drivers/cdrom/cdrom.c | 2 +- drivers/ide/ide-disk.c | 2 +- include/linux/blkdev.h | 4 ++-- 5 files changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index 874e46fc3748..d260a2ce9a70 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -2269,13 +2269,14 @@ void blk_execute_rq_nowait(request_queue_t *q, struct gendisk *bd_disk, * @q: queue to insert the request in * @bd_disk: matching gendisk * @rq: request to insert + * @at_head: insert request at head or tail of queue * * Description: * Insert a fully prepared request at the back of the io scheduler queue * for execution. */ int blk_execute_rq(request_queue_t *q, struct gendisk *bd_disk, - struct request *rq) + struct request *rq, int at_head) { DECLARE_COMPLETION(wait); char sense[SCSI_SENSE_BUFFERSIZE]; @@ -2294,7 +2295,7 @@ int blk_execute_rq(request_queue_t *q, struct gendisk *bd_disk, } rq->waiting = &wait; - blk_execute_rq_nowait(q, bd_disk, rq, 0, blk_end_sync_rq); + blk_execute_rq_nowait(q, bd_disk, rq, at_head, blk_end_sync_rq); wait_for_completion(&wait); rq->waiting = NULL; @@ -2361,7 +2362,7 @@ int blkdev_scsi_issue_flush_fn(request_queue_t *q, struct gendisk *disk, rq->data_len = 0; rq->timeout = 60 * HZ; - ret = blk_execute_rq(q, disk, rq); + ret = blk_execute_rq(q, disk, rq, 0); if (ret && error_sector) *error_sector = rq->sector; diff --git a/drivers/block/scsi_ioctl.c b/drivers/block/scsi_ioctl.c index 7717b76f7f20..abb2df249fd3 100644 --- a/drivers/block/scsi_ioctl.c +++ b/drivers/block/scsi_ioctl.c @@ -308,7 +308,7 @@ static int sg_io(struct file *file, request_queue_t *q, * (if he doesn't check that is his problem). * N.B. a non-zero SCSI status is _not_ necessarily an error. */ - blk_execute_rq(q, bd_disk, rq); + blk_execute_rq(q, bd_disk, rq, 0); /* write to all output members */ hdr->status = 0xff & rq->errors; @@ -420,7 +420,7 @@ static int sg_scsi_ioctl(struct file *file, request_queue_t *q, rq->data_len = bytes; rq->flags |= REQ_BLOCK_PC; - blk_execute_rq(q, bd_disk, rq); + blk_execute_rq(q, bd_disk, rq, 0); err = rq->errors & 0xff; /* only 8 bit SCSI status */ if (err) { if (rq->sense_len && rq->sense) { @@ -573,7 +573,7 @@ int scsi_cmd_ioctl(struct file *file, struct gendisk *bd_disk, unsigned int cmd, rq->cmd[0] = GPCMD_START_STOP_UNIT; rq->cmd[4] = 0x02 + (close != 0); rq->cmd_len = 6; - err = blk_execute_rq(q, bd_disk, rq); + err = blk_execute_rq(q, bd_disk, rq, 0); blk_put_request(rq); break; default: diff --git a/drivers/cdrom/cdrom.c b/drivers/cdrom/cdrom.c index 6a7d926774a1..153960348414 100644 --- a/drivers/cdrom/cdrom.c +++ b/drivers/cdrom/cdrom.c @@ -2136,7 +2136,7 @@ static int cdrom_read_cdda_bpc(struct cdrom_device_info *cdi, __u8 __user *ubuf, if (rq->bio) blk_queue_bounce(q, &rq->bio); - if (blk_execute_rq(q, cdi->disk, rq)) { + if (blk_execute_rq(q, cdi->disk, rq, 0)) { struct request_sense *s = rq->sense; ret = -EIO; cdi->last_sense = s->sense_key; diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index 3302cd8eab4c..9176da7a9858 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -750,7 +750,7 @@ static int idedisk_issue_flush(request_queue_t *q, struct gendisk *disk, idedisk_prepare_flush(q, rq); - ret = blk_execute_rq(q, disk, rq); + ret = blk_execute_rq(q, disk, rq, 0); /* * if we failed and caller wants error offset, get it diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 0430ea3e5f2e..a48dc12c6699 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -562,8 +562,8 @@ extern int blk_rq_map_user(request_queue_t *, struct request *, void __user *, u extern int blk_rq_unmap_user(struct bio *, unsigned int); extern int blk_rq_map_kern(request_queue_t *, struct request *, void *, unsigned int, unsigned int); extern int blk_rq_map_user_iov(request_queue_t *, struct request *, struct sg_iovec *, int); -extern int blk_execute_rq(request_queue_t *, struct gendisk *, struct request *); - +extern int blk_execute_rq(request_queue_t *, struct gendisk *, + struct request *, int); static inline request_queue_t *bdev_get_queue(struct block_device *bdev) { return bdev->bd_disk->queue; From 73747aed04d3b3fb694961d025f81863b99c6898 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 20 Jun 2005 14:21:01 +0200 Subject: [PATCH 008/114] [PATCH] ll_rw_blk.c kerneldoc updates The recent mapping changes didn't update the kerneldoc appropriately. Original from Christoph Hellwig Signed-off-by: Jens Axboe --- drivers/block/ll_rw_blk.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c index d260a2ce9a70..f6fda036b4ae 100644 --- a/drivers/block/ll_rw_blk.c +++ b/drivers/block/ll_rw_blk.c @@ -2090,7 +2090,7 @@ EXPORT_SYMBOL(blk_insert_request); /** * blk_rq_map_user - map user data to a request, for REQ_BLOCK_PC usage * @q: request queue where request should be inserted - * @rw: READ or WRITE data + * @rq: request structure to fill * @ubuf: the user buffer * @len: length of user data * @@ -2194,12 +2194,11 @@ EXPORT_SYMBOL(blk_rq_map_user_iov); /** * blk_rq_unmap_user - unmap a request with user data - * @rq: request to be unmapped - * @bio: bio for the request + * @bio: bio to be unmapped * @ulen: length of user buffer * * Description: - * Unmap a request previously mapped by blk_rq_map_user(). + * Unmap a bio previously mapped by blk_rq_map_user(). */ int blk_rq_unmap_user(struct bio *bio, unsigned int ulen) { @@ -2220,9 +2219,10 @@ EXPORT_SYMBOL(blk_rq_unmap_user); /** * blk_rq_map_kern - map kernel data to a request, for REQ_BLOCK_PC usage * @q: request queue where request should be inserted - * @rw: READ or WRITE data + * @rq: request to fill * @kbuf: the kernel buffer * @len: length of user data + * @gfp_mask: memory allocation flags */ int blk_rq_map_kern(request_queue_t *q, struct request *rq, void *kbuf, unsigned int len, unsigned int gfp_mask) @@ -2251,6 +2251,18 @@ int blk_rq_map_kern(request_queue_t *q, struct request *rq, void *kbuf, EXPORT_SYMBOL(blk_rq_map_kern); +/** + * blk_execute_rq_nowait - insert a request into queue for execution + * @q: queue to insert the request in + * @bd_disk: matching gendisk + * @rq: request to insert + * @at_head: insert request at head or tail of queue + * @done: I/O completion handler + * + * Description: + * Insert a fully prepared request at the back of the io scheduler queue + * for execution. Don't wait for completion. + */ void blk_execute_rq_nowait(request_queue_t *q, struct gendisk *bd_disk, struct request *rq, int at_head, void (*done)(struct request *)) @@ -2273,7 +2285,7 @@ void blk_execute_rq_nowait(request_queue_t *q, struct gendisk *bd_disk, * * Description: * Insert a fully prepared request at the back of the io scheduler queue - * for execution. + * for execution and wait for completion. */ int blk_execute_rq(request_queue_t *q, struct gendisk *bd_disk, struct request *rq, int at_head) From 0a637a2cec724eeb4649f6d1c07026b72c39ad84 Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Tue, 19 Jul 2005 22:04:24 +0200 Subject: [PATCH 009/114] [SCSI] aic byteorder fixes after recent cleanup aic doesnt work anymore after this change which appeared int 2.6.13-rc1: [SCSI] aic7xxx/aic79xx: remove useless byte order macro cruft 2 files did not include byteorder.h, aic died with panic "Unknown opcode encountered in seq program" This patch fixes it for me. Signed-off-by: Olaf Hering Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aicasm/aicasm.c | 4 ++-- drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h | 8 +++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm.c b/drivers/scsi/aic7xxx/aicasm/aicasm.c index c34639481904..f936b691232f 100644 --- a/drivers/scsi/aic7xxx/aicasm/aicasm.c +++ b/drivers/scsi/aic7xxx/aicasm/aicasm.c @@ -369,7 +369,7 @@ output_code() fprintf(ofile, "%s\t0x%02x, 0x%02x, 0x%02x, 0x%02x", cur_instr == STAILQ_FIRST(&seq_program) ? "" : ",\n", -#if BYTE_ORDER == LITTLE_ENDIAN +#ifdef __LITTLE_ENDIAN cur_instr->format.bytes[0], cur_instr->format.bytes[1], cur_instr->format.bytes[2], @@ -613,7 +613,7 @@ output_listing(char *ifilename) line++; } fprintf(listfile, "%03x %02x%02x%02x%02x", instrptr, -#if BYTE_ORDER == LITTLE_ENDIAN +#ifdef __LITTLE_ENDIAN cur_instr->format.bytes[0], cur_instr->format.bytes[1], cur_instr->format.bytes[2], diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h b/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h index 3e80f07df49c..e64f802bbaaa 100644 --- a/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h +++ b/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h @@ -42,8 +42,10 @@ * $FreeBSD$ */ +#include + struct ins_format1 { -#if BYTE_ORDER == LITTLE_ENDIAN +#ifdef __LITTLE_ENDIAN uint32_t immediate : 8, source : 9, destination : 9, @@ -61,7 +63,7 @@ struct ins_format1 { }; struct ins_format2 { -#if BYTE_ORDER == LITTLE_ENDIAN +#ifdef __LITTLE_ENDIAN uint32_t shift_control : 8, source : 9, destination : 9, @@ -79,7 +81,7 @@ struct ins_format2 { }; struct ins_format3 { -#if BYTE_ORDER == LITTLE_ENDIAN +#ifdef __LITTLE_ENDIAN uint32_t immediate : 8, source : 9, address : 10, From 5dbffcd83d826a9b42a10afb89b13156dc5b9539 Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Wed, 27 Jul 2005 01:07:42 -0700 Subject: [PATCH 010/114] [SCSI] git-scsi-misc: drivers/scsi/ch.c: remove devfs stuff It seems very unlikely that this driver will go into any stable kernel before devfs will be removed. Signed-off-by: Adrian Bunk Cc: James Bottomley Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/ch.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c index 3900e28ac7d6..53b395534313 100644 --- a/drivers/scsi/ch.c +++ b/drivers/scsi/ch.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include /* here are all the ioctls */ @@ -940,8 +939,6 @@ static int ch_probe(struct device *dev) if (init) ch_init_elem(ch); - devfs_mk_cdev(MKDEV(SCSI_CHANGER_MAJOR,ch->minor), - S_IFCHR | S_IRUGO | S_IWUGO, ch->name); class_device_create(ch_sysfs_class, MKDEV(SCSI_CHANGER_MAJOR,ch->minor), dev, "s%s", ch->name); @@ -974,7 +971,6 @@ static int ch_remove(struct device *dev) class_device_destroy(ch_sysfs_class, MKDEV(SCSI_CHANGER_MAJOR,ch->minor)); - devfs_remove(ch->name); kfree(ch->dt); kfree(ch); ch_devcount--; From d3301874083874f8a0ac88aa1bb7da6b62df34d2 Mon Sep 17 00:00:00 2001 From: Mike Anderson Date: Thu, 16 Jun 2005 11:12:38 -0700 Subject: [PATCH 011/114] [SCSI] host state model update: replace old host bitmap state Migrate the current SCSI host state model to a model like SCSI device is using. Signed-off-by: Mike Anderson Rejections fixed up and Signed-off-by: James Bottomley --- drivers/scsi/hosts.c | 88 ++++++++++++++++++++++++++++++++++++--- drivers/scsi/scsi.c | 2 +- drivers/scsi/scsi_error.c | 7 ++-- drivers/scsi/scsi_ioctl.c | 3 +- drivers/scsi/scsi_lib.c | 4 +- drivers/scsi/scsi_sysfs.c | 62 +++++++++++++++++++++++++++ drivers/scsi/sg.c | 3 +- include/scsi/scsi_host.h | 14 ++++--- 8 files changed, 162 insertions(+), 21 deletions(-) diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 5feb886c3392..6828ca305c2a 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -51,6 +51,82 @@ static struct class shost_class = { .release = scsi_host_cls_release, }; +/** + * scsi_host_set_state - Take the given host through the host + * state model. + * @shost: scsi host to change the state of. + * @state: state to change to. + * + * Returns zero if unsuccessful or an error if the requested + * transition is illegal. + **/ +int scsi_host_set_state(struct Scsi_Host *shost, enum scsi_host_state state) +{ + enum scsi_host_state oldstate = shost->shost_state; + + if (state == oldstate) + return 0; + + switch (state) { + case SHOST_CREATED: + /* There are no legal states that come back to + * created. This is the manually initialised start + * state */ + goto illegal; + + case SHOST_RUNNING: + switch (oldstate) { + case SHOST_CREATED: + case SHOST_RECOVERY: + break; + default: + goto illegal; + } + break; + + case SHOST_RECOVERY: + switch (oldstate) { + case SHOST_RUNNING: + break; + default: + goto illegal; + } + break; + + case SHOST_CANCEL: + switch (oldstate) { + case SHOST_CREATED: + case SHOST_RUNNING: + break; + default: + goto illegal; + } + break; + + case SHOST_DEL: + switch (oldstate) { + case SHOST_CANCEL: + break; + default: + goto illegal; + } + break; + + } + shost->shost_state = state; + return 0; + + illegal: + SCSI_LOG_ERROR_RECOVERY(1, + dev_printk(KERN_ERR, &shost->shost_gendev, + "Illegal host state transition" + "%s->%s\n", + scsi_host_state_name(oldstate), + scsi_host_state_name(state))); + return -EINVAL; +} +EXPORT_SYMBOL(scsi_host_set_state); + /** * scsi_host_cancel - cancel outstanding IO to this host * @shost: pointer to struct Scsi_Host @@ -60,12 +136,11 @@ static void scsi_host_cancel(struct Scsi_Host *shost, int recovery) { struct scsi_device *sdev; - set_bit(SHOST_CANCEL, &shost->shost_state); + scsi_host_set_state(shost, SHOST_CANCEL); shost_for_each_device(sdev, shost) { scsi_device_cancel(sdev, recovery); } - wait_event(shost->host_wait, (!test_bit(SHOST_RECOVERY, - &shost->shost_state))); + wait_event(shost->host_wait, (shost->shost_state != SHOST_RECOVERY)); } /** @@ -78,7 +153,7 @@ void scsi_remove_host(struct Scsi_Host *shost) scsi_host_cancel(shost, 0); scsi_proc_host_rm(shost); - set_bit(SHOST_DEL, &shost->shost_state); + scsi_host_set_state(shost, SHOST_DEL); transport_unregister_device(&shost->shost_gendev); class_device_unregister(&shost->shost_classdev); @@ -115,7 +190,7 @@ int scsi_add_host(struct Scsi_Host *shost, struct device *dev) if (error) goto out; - set_bit(SHOST_ADD, &shost->shost_state); + scsi_host_set_state(shost, SHOST_RUNNING); get_device(shost->shost_gendev.parent); error = class_device_add(&shost->shost_classdev); @@ -226,6 +301,7 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) spin_lock_init(&shost->default_lock); scsi_assign_lock(shost, &shost->default_lock); + shost->shost_state = SHOST_CREATED; INIT_LIST_HEAD(&shost->__devices); INIT_LIST_HEAD(&shost->__targets); INIT_LIST_HEAD(&shost->eh_cmd_q); @@ -382,7 +458,7 @@ EXPORT_SYMBOL(scsi_host_lookup); **/ struct Scsi_Host *scsi_host_get(struct Scsi_Host *shost) { - if (test_bit(SHOST_DEL, &shost->shost_state) || + if ((shost->shost_state == SHOST_DEL) || !get_device(&shost->shost_gendev)) return NULL; return shost; diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index d14523d7e449..fb85b3ced7b5 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -627,7 +627,7 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd) spin_lock_irqsave(host->host_lock, flags); scsi_cmd_get_serial(host, cmd); - if (unlikely(test_bit(SHOST_CANCEL, &host->shost_state))) { + if (unlikely(host->shost_state == SHOST_CANCEL)) { cmd->result = (DID_NO_CONNECT << 16); scsi_done(cmd); } else { diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 0fc8b48f052b..e9c451ba71fc 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -75,7 +75,7 @@ int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag) scmd->eh_eflags |= eh_flag; list_add_tail(&scmd->eh_entry, &shost->eh_cmd_q); - set_bit(SHOST_RECOVERY, &shost->shost_state); + scsi_host_set_state(shost, SHOST_RECOVERY); shost->host_failed++; scsi_eh_wakeup(shost); spin_unlock_irqrestore(shost->host_lock, flags); @@ -197,7 +197,8 @@ int scsi_block_when_processing_errors(struct scsi_device *sdev) { int online; - wait_event(sdev->host->host_wait, (!test_bit(SHOST_RECOVERY, &sdev->host->shost_state))); + wait_event(sdev->host->host_wait, (sdev->host->shost_state != + SHOST_RECOVERY)); online = scsi_device_online(sdev); @@ -1458,7 +1459,7 @@ static void scsi_restart_operations(struct Scsi_Host *shost) SCSI_LOG_ERROR_RECOVERY(3, printk("%s: waking up host to restart\n", __FUNCTION__)); - clear_bit(SHOST_RECOVERY, &shost->shost_state); + scsi_host_set_state(shost, SHOST_RUNNING); wake_up(&shost->host_wait); diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index 7a6b530115ac..f5bf5c07be91 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c @@ -475,8 +475,7 @@ int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd, * error processing, as long as the device was opened * non-blocking */ if (filp && filp->f_flags & O_NONBLOCK) { - if (test_bit(SHOST_RECOVERY, - &sdev->host->shost_state)) + if (sdev->host->shost_state == SHOST_RECOVERY) return -ENODEV; } else if (!scsi_block_when_processing_errors(sdev)) return -ENODEV; diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 7a91ca3d32a6..060010bccabc 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -348,7 +348,7 @@ void scsi_device_unbusy(struct scsi_device *sdev) spin_lock_irqsave(shost->host_lock, flags); shost->host_busy--; - if (unlikely(test_bit(SHOST_RECOVERY, &shost->shost_state) && + if (unlikely((shost->shost_state == SHOST_RECOVERY) && shost->host_failed)) scsi_eh_wakeup(shost); spin_unlock(shost->host_lock); @@ -1207,7 +1207,7 @@ static inline int scsi_host_queue_ready(struct request_queue *q, struct Scsi_Host *shost, struct scsi_device *sdev) { - if (test_bit(SHOST_RECOVERY, &shost->shost_state)) + if (shost->shost_state == SHOST_RECOVERY) return 0; if (shost->host_busy == 0 && shost->host_blocked) { /* diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index beed7fbe1cbe..dae59d1da07a 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -48,6 +48,30 @@ const char *scsi_device_state_name(enum scsi_device_state state) return name; } +static struct { + enum scsi_host_state value; + char *name; +} shost_states[] = { + { SHOST_CREATED, "created" }, + { SHOST_RUNNING, "running" }, + { SHOST_CANCEL, "cancel" }, + { SHOST_DEL, "deleted" }, + { SHOST_RECOVERY, "recovery" }, +}; +const char *scsi_host_state_name(enum scsi_host_state state) +{ + int i; + char *name = NULL; + + for (i = 0; i < sizeof(shost_states)/sizeof(shost_states[0]); i++) { + if (shost_states[i].value == state) { + name = shost_states[i].name; + break; + } + } + return name; +} + static int check_set(unsigned int *val, char *src) { char *last; @@ -124,6 +148,43 @@ static ssize_t store_scan(struct class_device *class_dev, const char *buf, }; static CLASS_DEVICE_ATTR(scan, S_IWUSR, NULL, store_scan); +static ssize_t +store_shost_state(struct class_device *class_dev, const char *buf, size_t count) +{ + int i; + struct Scsi_Host *shost = class_to_shost(class_dev); + enum scsi_host_state state = 0; + + for (i = 0; i < sizeof(shost_states)/sizeof(shost_states[0]); i++) { + const int len = strlen(shost_states[i].name); + if (strncmp(shost_states[i].name, buf, len) == 0 && + buf[len] == '\n') { + state = shost_states[i].value; + break; + } + } + if (!state) + return -EINVAL; + + if (scsi_host_set_state(shost, state)) + return -EINVAL; + return count; +} + +static ssize_t +show_shost_state(struct class_device *class_dev, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(class_dev); + const char *name = scsi_host_state_name(shost->shost_state); + + if (!name) + return -EINVAL; + + return snprintf(buf, 20, "%s\n", name); +} + +static CLASS_DEVICE_ATTR(state, S_IRUGO | S_IWUSR, show_shost_state, store_shost_state); + shost_rd_attr(unique_id, "%u\n"); shost_rd_attr(host_busy, "%hu\n"); shost_rd_attr(cmd_per_lun, "%hd\n"); @@ -139,6 +200,7 @@ static struct class_device_attribute *scsi_sysfs_shost_attrs[] = { &class_device_attr_unchecked_isa_dma, &class_device_attr_proc_name, &class_device_attr_scan, + &class_device_attr_state, NULL }; diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 51292f269ce5..14fb179b3842 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -1027,8 +1027,7 @@ sg_ioctl(struct inode *inode, struct file *filp, if (sdp->detached) return -ENODEV; if (filp->f_flags & O_NONBLOCK) { - if (test_bit(SHOST_RECOVERY, - &sdp->device->host->shost_state)) + if (sdp->device->host->shost_state == SHOST_RECOVERY) return -EBUSY; } else if (!scsi_block_when_processing_errors(sdp->device)) return -EBUSY; diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index 81d5234f6771..0b1e275b2699 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -429,12 +429,15 @@ struct scsi_host_template { }; /* - * shost states + * shost state: If you alter this, you also need to alter scsi_sysfs.c + * (for the ascii descriptions) and the state model enforcer: + * scsi_host_set_state() */ -enum { - SHOST_ADD, - SHOST_DEL, +enum scsi_host_state { + SHOST_CREATED = 1, + SHOST_RUNNING, SHOST_CANCEL, + SHOST_DEL, SHOST_RECOVERY, }; @@ -575,7 +578,7 @@ struct Scsi_Host { unsigned int irq; - unsigned long shost_state; + enum scsi_host_state shost_state; /* ldm bits */ struct device shost_gendev; @@ -633,6 +636,7 @@ extern void scsi_remove_host(struct Scsi_Host *); extern struct Scsi_Host *scsi_host_get(struct Scsi_Host *); extern void scsi_host_put(struct Scsi_Host *t); extern struct Scsi_Host *scsi_host_lookup(unsigned short); +extern const char *scsi_host_state_name(enum scsi_host_state); extern u64 scsi_calculate_bounce_limit(struct Scsi_Host *); From d2c9d9eafa03dbd08a8a439e6c5addb8b1f03b9b Mon Sep 17 00:00:00 2001 From: Mike Anderson Date: Thu, 16 Jun 2005 11:13:42 -0700 Subject: [PATCH 012/114] [SCSI] host state model update: reimplement scsi_host_cancel Remove the old scsi_host_cancel function as it has not been working for sometime do to the device list possibly being empty when it is called and possible race issues. Add setting of SHOST_CANCEL at the state of beginning of scsi_remove_host. Signed-off-by: Mike Anderson Signed-off-by: James Bottomley --- drivers/scsi/hosts.c | 18 +----------------- drivers/scsi/scsi.c | 2 +- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 6828ca305c2a..67c4c0c3aa5e 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -127,30 +127,14 @@ int scsi_host_set_state(struct Scsi_Host *shost, enum scsi_host_state state) } EXPORT_SYMBOL(scsi_host_set_state); -/** - * scsi_host_cancel - cancel outstanding IO to this host - * @shost: pointer to struct Scsi_Host - * recovery: recovery requested to run. - **/ -static void scsi_host_cancel(struct Scsi_Host *shost, int recovery) -{ - struct scsi_device *sdev; - - scsi_host_set_state(shost, SHOST_CANCEL); - shost_for_each_device(sdev, shost) { - scsi_device_cancel(sdev, recovery); - } - wait_event(shost->host_wait, (shost->shost_state != SHOST_RECOVERY)); -} - /** * scsi_remove_host - remove a scsi host * @shost: a pointer to a scsi host to remove **/ void scsi_remove_host(struct Scsi_Host *shost) { + scsi_host_set_state(shost, SHOST_CANCEL); scsi_forget_host(shost); - scsi_host_cancel(shost, 0); scsi_proc_host_rm(shost); scsi_host_set_state(shost, SHOST_DEL); diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index fb85b3ced7b5..d1aa95d45a70 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -627,7 +627,7 @@ int scsi_dispatch_cmd(struct scsi_cmnd *cmd) spin_lock_irqsave(host->host_lock, flags); scsi_cmd_get_serial(host, cmd); - if (unlikely(host->shost_state == SHOST_CANCEL)) { + if (unlikely(host->shost_state == SHOST_DEL)) { cmd->result = (DID_NO_CONNECT << 16); scsi_done(cmd); } else { From 82f29467a025f6a2192d281e97fca0be46e905cc Mon Sep 17 00:00:00 2001 From: Mike Anderson Date: Thu, 16 Jun 2005 11:14:33 -0700 Subject: [PATCH 013/114] [SCSI] host state model update: mediate host add/remove race Add support to not allow additions to a host when it is being removed. Signed-off-by: Mike Anderson Signed-off-by: James Bottomley --- drivers/scsi/hosts.c | 2 ++ drivers/scsi/scsi_scan.c | 21 ++++++++++++++------- include/scsi/scsi_host.h | 9 +++++++++ 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 67c4c0c3aa5e..8640ad1c17e2 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -133,7 +133,9 @@ EXPORT_SYMBOL(scsi_host_set_state); **/ void scsi_remove_host(struct Scsi_Host *shost) { + down(&shost->scan_mutex); scsi_host_set_state(shost, SHOST_CANCEL); + up(&shost->scan_mutex); scsi_forget_host(shost); scsi_proc_host_rm(shost); diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 2d3c4ac475f2..076cbe3b5a05 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -1251,9 +1251,12 @@ struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel, get_device(&starget->dev); down(&shost->scan_mutex); - res = scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata); - if (res != SCSI_SCAN_LUN_PRESENT) - sdev = ERR_PTR(-ENODEV); + if (scsi_host_scan_allowed(shost)) { + res = scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, + hostdata); + if (res != SCSI_SCAN_LUN_PRESENT) + sdev = ERR_PTR(-ENODEV); + } up(&shost->scan_mutex); scsi_target_reap(starget); put_device(&starget->dev); @@ -1403,11 +1406,15 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel, return -EINVAL; down(&shost->scan_mutex); - if (channel == SCAN_WILD_CARD) - for (channel = 0; channel <= shost->max_channel; channel++) + if (scsi_host_scan_allowed(shost)) { + if (channel == SCAN_WILD_CARD) + for (channel = 0; channel <= shost->max_channel; + channel++) + scsi_scan_channel(shost, channel, id, lun, + rescan); + else scsi_scan_channel(shost, channel, id, lun, rescan); - else - scsi_scan_channel(shost, channel, id, lun, rescan); + } up(&shost->scan_mutex); return 0; diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index 0b1e275b2699..1ea5b51d1749 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -650,6 +650,15 @@ static inline struct device *scsi_get_device(struct Scsi_Host *shost) return shost->shost_gendev.parent; } +/** + * scsi_host_scan_allowed - Is scanning of this host allowed + * @shost: Pointer to Scsi_Host. + **/ +static inline int scsi_host_scan_allowed(struct Scsi_Host *shost) +{ + return shost->shost_state == SHOST_RUNNING; +} + extern void scsi_unblock_requests(struct Scsi_Host *); extern void scsi_block_requests(struct Scsi_Host *); From 47ba39eead9f4495cd6a3eca39d7c73d0f0d61c9 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sat, 30 Jul 2005 11:39:53 -0500 Subject: [PATCH 014/114] [SCSI] add template for scsi_host_set_state() Fixes up some warnings in the tree. Signed-off-by: James Bottomley --- include/scsi/scsi_host.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index 1ea5b51d1749..ac1b6125e3ae 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -676,5 +676,6 @@ extern struct scsi_device *scsi_get_host_dev(struct Scsi_Host *); /* legacy interfaces */ extern struct Scsi_Host *scsi_register(struct scsi_host_template *, int); extern void scsi_unregister(struct Scsi_Host *); +extern int scsi_host_set_state(struct Scsi_Host *, enum scsi_host_state); #endif /* _SCSI_SCSI_HOST_H */ From a6c42741ace2fee235b6902e76f3c86a01d32146 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 4 Jul 2005 17:48:13 +0200 Subject: [PATCH 015/114] [SCSI] qla1280: remove dead per-host flag variables Signed-off-by: Christoph Hellwig Signed-off-by: Thiemo Seufer Signed-off-by: James Bottomley --- drivers/scsi/qla1280.c | 7 ------- drivers/scsi/qla1280.h | 4 ---- 2 files changed, 11 deletions(-) diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index b993652bfa25..eb5543ef513b 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -996,7 +996,6 @@ qla1280_error_action(struct scsi_cmnd *cmd, enum action action) break; case ABORT_DEVICE: - ha->flags.in_reset = 1; if (qla1280_verbose) printk(KERN_INFO "scsi(%ld:%d:%d:%d): Queueing abort device " @@ -1010,7 +1009,6 @@ qla1280_error_action(struct scsi_cmnd *cmd, enum action action) printk(KERN_INFO "scsi(%ld:%d:%d:%d): Queueing device reset " "command.\n", ha->host_no, bus, target, lun); - ha->flags.in_reset = 1; if (qla1280_device_reset(ha, bus, target) == 0) result = SUCCESS; break; @@ -1019,7 +1017,6 @@ qla1280_error_action(struct scsi_cmnd *cmd, enum action action) if (qla1280_verbose) printk(KERN_INFO "qla1280(%ld:%d): Issuing BUS " "DEVICE RESET\n", ha->host_no, bus); - ha->flags.in_reset = 1; if (qla1280_bus_reset(ha, bus == 0)) result = SUCCESS; @@ -1047,7 +1044,6 @@ qla1280_error_action(struct scsi_cmnd *cmd, enum action action) if (!list_empty(&ha->done_q)) qla1280_done(ha); - ha->flags.in_reset = 0; /* If we didn't manage to issue the action, or we have no * command to wait for, exit here */ @@ -1636,7 +1632,6 @@ qla1280_enable_intrs(struct scsi_qla_host *ha) /* enable risc and host interrupts */ WRT_REG_WORD(®->ictrl, (ISP_EN_INT | ISP_EN_RISC)); RD_REG_WORD(®->ictrl); /* PCI Posted Write flush */ - ha->flags.ints_enabled = 1; } static inline void @@ -1648,7 +1643,6 @@ qla1280_disable_intrs(struct scsi_qla_host *ha) /* disable risc and host interrupts */ WRT_REG_WORD(®->ictrl, 0); RD_REG_WORD(®->ictrl); /* PCI Posted Write flush */ - ha->flags.ints_enabled = 0; } /* @@ -1679,7 +1673,6 @@ qla1280_initialize_adapter(struct scsi_qla_host *ha) ha->flags.reset_active = 0; ha->flags.abort_isp_active = 0; - ha->flags.ints_enabled = 0; #if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2) if (ia64_platform_is("sn2")) { printk(KERN_INFO "scsi(%li): Enabling SN2 PCI DMA " diff --git a/drivers/scsi/qla1280.h b/drivers/scsi/qla1280.h index d245ae07518e..1c1cf3a5af03 100644 --- a/drivers/scsi/qla1280.h +++ b/drivers/scsi/qla1280.h @@ -1082,10 +1082,6 @@ struct scsi_qla_host { uint32_t reset_active:1; /* 3 */ uint32_t abort_isp_active:1; /* 4 */ uint32_t disable_risc_code_load:1; /* 5 */ - uint32_t enable_64bit_addressing:1; /* 6 */ - uint32_t in_reset:1; /* 7 */ - uint32_t ints_enabled:1; - uint32_t ignore_nvram:1; #ifdef __ia64__ uint32_t use_pci_vchannel:1; #endif From 8af50dcd22aa0a5840f18276ff10a6977abc3853 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 4 Jul 2005 17:48:19 +0200 Subject: [PATCH 016/114] [SCSI] qla1280: interupt posting for irq disabling/enabling Signed-off-by: Christoph Hellwig Signed-off-by: Thiemo Seufer Signed-off-by: James Bottomley --- drivers/scsi/qla1280.c | 57 +++++++++++++++--------------------------- 1 file changed, 20 insertions(+), 37 deletions(-) diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index eb5543ef513b..58ecdc696675 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -1265,6 +1265,22 @@ qla1280_biosparam_old(Disk * disk, kdev_t dev, int geom[]) return qla1280_biosparam(disk->device, NULL, disk->capacity, geom); } #endif + +/* disable risc and host interrupts */ +static inline void +qla1280_disable_intrs(struct scsi_qla_host *ha) +{ + WRT_REG_WORD(&ha->iobase->ictrl, 0); + RD_REG_WORD(&ha->iobase->ictrl); /* PCI Posted Write flush */ +} + +/* enable risc and host interrupts */ +static inline void +qla1280_enable_intrs(struct scsi_qla_host *ha) +{ + WRT_REG_WORD(&ha->iobase->ictrl, (ISP_EN_INT | ISP_EN_RISC)); + RD_REG_WORD(&ha->iobase->ictrl); /* PCI Posted Write flush */ +} /************************************************************************** * qla1280_intr_handler @@ -1286,7 +1302,7 @@ qla1280_intr_handler(int irq, void *dev_id, struct pt_regs *regs) ha->isr_count++; reg = ha->iobase; - WRT_REG_WORD(®->ictrl, 0); /* disable our interrupt. */ + qla1280_disable_intrs(ha); data = qla1280_debounce_register(®->istatus); /* Check for pending interrupts. */ @@ -1299,8 +1315,7 @@ qla1280_intr_handler(int irq, void *dev_id, struct pt_regs *regs) spin_unlock(HOST_LOCK); - /* enable our interrupt. */ - WRT_REG_WORD(®->ictrl, (ISP_EN_INT | ISP_EN_RISC)); + qla1280_enable_intrs(ha); LEAVE_INTR("qla1280_intr_handler"); return IRQ_RETVAL(handled); @@ -1613,38 +1628,6 @@ qla1280_return_status(struct response * sts, struct scsi_cmnd *cp) /* QLogic ISP1280 Hardware Support Functions. */ /****************************************************************************/ - /* - * qla2100_enable_intrs - * qla2100_disable_intrs - * - * Input: - * ha = adapter block pointer. - * - * Returns: - * None - */ -static inline void -qla1280_enable_intrs(struct scsi_qla_host *ha) -{ - struct device_reg __iomem *reg; - - reg = ha->iobase; - /* enable risc and host interrupts */ - WRT_REG_WORD(®->ictrl, (ISP_EN_INT | ISP_EN_RISC)); - RD_REG_WORD(®->ictrl); /* PCI Posted Write flush */ -} - -static inline void -qla1280_disable_intrs(struct scsi_qla_host *ha) -{ - struct device_reg __iomem *reg; - - reg = ha->iobase; - /* disable risc and host interrupts */ - WRT_REG_WORD(®->ictrl, 0); - RD_REG_WORD(®->ictrl); /* PCI Posted Write flush */ -} - /* * qla1280_initialize_adapter * Initialize board. @@ -4751,7 +4734,7 @@ qla1280_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) #if LINUX_VERSION_CODE >= 0x020600 error_disable_adapter: - WRT_REG_WORD(&ha->iobase->ictrl, 0); + qla1280_disable_intrs(ha); #endif error_free_irq: free_irq(pdev->irq, ha); @@ -4788,7 +4771,7 @@ qla1280_remove_one(struct pci_dev *pdev) scsi_remove_host(host); #endif - WRT_REG_WORD(&ha->iobase->ictrl, 0); + qla1280_disable_intrs(ha); free_irq(pdev->irq, ha); From 2b55cac3d2d9f545c141748d00eae86e2c042ca5 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 4 Jul 2005 17:48:30 +0200 Subject: [PATCH 017/114] [SCSI] qla1280: misc cleanups print message tidy ups and some excess brace removal. Signed-off-by: Christoph Hellwig Signed-off-by: Thiemo Seufer Signed-off-by: James Bottomley --- drivers/scsi/qla1280.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 58ecdc696675..e5354550d762 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -1459,7 +1459,6 @@ qla1280_select_queue_depth(struct Scsi_Host *host, struct scsi_device *sdev_q) * * Input: * ha = adapter block pointer. - * done_q = done queue. */ static void qla1280_done(struct scsi_qla_host *ha) @@ -1593,7 +1592,7 @@ qla1280_return_status(struct response * sts, struct scsi_cmnd *cp) case CS_DATA_OVERRUN: dprintk(2, "Data overrun 0x%x\n", residual_length); - dprintk(2, "qla1280_isr: response packet data\n"); + dprintk(2, "qla1280_return_status: response packet data\n"); qla1280_dump_buffer(2, (char *)sts, RESPONSE_ENTRY_SIZE); host_status = DID_ERROR; break; @@ -2061,7 +2060,7 @@ qla1280_start_firmware(struct scsi_qla_host *ha) mb[1] = *ql1280_board_tbl[ha->devnum].fwstart; err = qla1280_mailbox_command(ha, BIT_1 | BIT_0, mb); if (err) { - printk(KERN_ERR "scsi(%li): Failed checksum\n", ha->host_no); + printk(KERN_ERR "scsi(%li): RISC checksum failed.\n", ha->host_no); return err; } @@ -3080,10 +3079,13 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) REQUEST_ENTRY_CNT - (ha->req_ring_index - cnt); } + dprintk(3, "Number of free entries=(%d) seg_cnt=0x%x\n", + ha->req_q_cnt, seg_cnt); + /* If room for request in request ring. */ if ((req_cnt + 2) >= ha->req_q_cnt) { status = 1; - dprintk(2, "qla1280_64bit_start_scsi: in-ptr=0x%x req_q_cnt=" + dprintk(2, "qla1280_start_scsi: in-ptr=0x%x req_q_cnt=" "0x%xreq_cnt=0x%x", ha->req_ring_index, ha->req_q_cnt, req_cnt); goto out; @@ -3095,7 +3097,7 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) if (cnt >= MAX_OUTSTANDING_COMMANDS) { status = 1; - dprintk(2, "qla1280_64bit_start_scsi: NO ROOM IN " + dprintk(2, "qla1280_start_scsi: NO ROOM IN " "OUTSTANDING ARRAY, req_q_cnt=0x%x", ha->req_q_cnt); goto out; } @@ -3104,7 +3106,7 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) ha->req_q_cnt -= req_cnt; CMD_HANDLE(sp->cmd) = (unsigned char *)(unsigned long)(cnt + 1); - dprintk(2, "64bit_start: cmd=%p sp=%p CDB=%xm, handle %lx\n", cmd, sp, + dprintk(2, "start: cmd=%p sp=%p CDB=%xm, handle %lx\n", cmd, sp, cmd->cmnd[0], (long)CMD_HANDLE(sp->cmd)); dprintk(2, " bus %i, target %i, lun %i\n", SCSI_BUS_32(cmd), SCSI_TCN_32(cmd), SCSI_LUN_32(cmd)); @@ -4626,7 +4628,7 @@ qla1280_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) if (pci_set_dma_mask(ha->pdev, (dma_addr_t) ~ 0ULL)) { if (pci_set_dma_mask(ha->pdev, 0xffffffff)) { printk(KERN_WARNING "scsi(%li): Unable to set a " - " suitable DMA mask - aboring\n", ha->host_no); + "suitable DMA mask - aborting\n", ha->host_no); error = -ENODEV; goto error_free_irq; } @@ -4636,14 +4638,14 @@ qla1280_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) #else if (pci_set_dma_mask(ha->pdev, 0xffffffff)) { printk(KERN_WARNING "scsi(%li): Unable to set a " - " suitable DMA mask - aboring\n", ha->host_no); + "suitable DMA mask - aborting\n", ha->host_no); error = -ENODEV; goto error_free_irq; } #endif ha->request_ring = pci_alloc_consistent(ha->pdev, - ((REQUEST_ENTRY_CNT + 1) * (sizeof(request_t))), + ((REQUEST_ENTRY_CNT + 1) * sizeof(request_t)), &ha->request_dma); if (!ha->request_ring) { printk(KERN_INFO "qla1280: Failed to get request memory\n"); @@ -4651,7 +4653,7 @@ qla1280_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) } ha->response_ring = pci_alloc_consistent(ha->pdev, - ((RESPONSE_ENTRY_CNT + 1) * (sizeof(struct response))), + ((RESPONSE_ENTRY_CNT + 1) * sizeof(struct response)), &ha->response_dma); if (!ha->response_ring) { printk(KERN_INFO "qla1280: Failed to get response memory\n"); @@ -4746,11 +4748,11 @@ qla1280_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) #endif error_free_response_ring: pci_free_consistent(ha->pdev, - ((RESPONSE_ENTRY_CNT + 1) * (sizeof(struct response))), + ((RESPONSE_ENTRY_CNT + 1) * sizeof(struct response)), ha->response_ring, ha->response_dma); error_free_request_ring: pci_free_consistent(ha->pdev, - ((REQUEST_ENTRY_CNT + 1) * (sizeof(request_t))), + ((REQUEST_ENTRY_CNT + 1) * sizeof(request_t)), ha->request_ring, ha->request_dma); error_put_host: scsi_host_put(host); From d6db3e8d5fe3178776d0a0314e612c3f55e55fb4 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 4 Jul 2005 17:48:36 +0200 Subject: [PATCH 018/114] [SCSI] qla1280: use SAM_ constants Signed-off-by: Christoph Hellwig Signed-off-by: Thiemo Seufer Signed-off-by: James Bottomley --- drivers/scsi/qla1280.c | 2 +- drivers/scsi/qla1280.h | 8 -------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index e5354550d762..3732230b2e3a 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -4049,7 +4049,7 @@ qla1280_status_entry(struct scsi_qla_host *ha, struct response *pkt, /* Save ISP completion status */ CMD_RESULT(cmd) = qla1280_return_status(pkt, cmd); - if (scsi_status & SS_CHECK_CONDITION) { + if (scsi_status & SAM_STAT_CHECK_CONDITION) { if (comp_status != CS_ARS_FAILED) { uint16_t req_sense_length = le16_to_cpu(pkt->req_sense_length); diff --git a/drivers/scsi/qla1280.h b/drivers/scsi/qla1280.h index 1c1cf3a5af03..0d430d63be40 100644 --- a/drivers/scsi/qla1280.h +++ b/drivers/scsi/qla1280.h @@ -978,14 +978,6 @@ struct ctio_a64_ret_entry { #define CS_UNKNOWN 0x81 /* Driver defined */ #define CS_RETRY 0x82 /* Driver defined */ -/* - * ISP status entry - SCSI status byte bit definitions. - */ -#define SS_CHECK_CONDITION BIT_1 -#define SS_CONDITION_MET BIT_2 -#define SS_BUSY_CONDITION BIT_3 -#define SS_RESERVE_CONFLICT (BIT_4 | BIT_3) - /* * ISP target entries - Option flags bit definitions. */ From 748422d92a55faadf3184e5aa8487da88c1ee849 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 4 Jul 2005 17:48:41 +0200 Subject: [PATCH 019/114] [SCSI] qla1280: remove SG_SEGMENTS Signed-off-by: Christoph Hellwig Signed-off-by: Thiemo Seufer Signed-off-by: James Bottomley --- drivers/scsi/qla1280.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/scsi/qla1280.h b/drivers/scsi/qla1280.h index 0d430d63be40..18c20cf371af 100644 --- a/drivers/scsi/qla1280.h +++ b/drivers/scsi/qla1280.h @@ -94,9 +94,6 @@ #define REQUEST_ENTRY_CNT 256 /* Number of request entries. */ #define RESPONSE_ENTRY_CNT 16 /* Number of response entries. */ -/* Number of segments 1 - 65535 */ -#define SG_SEGMENTS 32 /* Cmd entry + 6 continuations */ - /* * SCSI Request Block structure (sp) that is placed * on cmd->SCp location of every I/O From 5c79d6154f335543ea4c4a555f645a1f76b5d117 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 4 Jul 2005 17:48:46 +0200 Subject: [PATCH 020/114] [SCSI] qla1280: always load microcode we have the most recent microcode, make sure to always load it. Signed-off-by: Christoph Hellwig Signed-off-by: James Bottomley --- drivers/scsi/qla1280.c | 72 +----------------------------------------- 1 file changed, 1 insertion(+), 71 deletions(-) diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 3732230b2e3a..9f975f7c1ea8 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -1733,69 +1733,6 @@ qla1280_initialize_adapter(struct scsi_qla_host *ha) return status; } - -/* - * ISP Firmware Test - * Checks if present version of RISC firmware is older than - * driver firmware. - * - * Input: - * ha = adapter block pointer. - * - * Returns: - * 0 = firmware does not need to be loaded. - */ -static int -qla1280_isp_firmware(struct scsi_qla_host *ha) -{ - struct nvram *nv = (struct nvram *) ha->response_ring; - int status = 0; /* dg 2/27 always loads RISC */ - uint16_t mb[MAILBOX_REGISTER_COUNT]; - - ENTER("qla1280_isp_firmware"); - - dprintk(1, "scsi(%li): Determining if RISC is loaded\n", ha->host_no); - - /* Bad NVRAM data, load RISC code. */ - if (!ha->nvram_valid) { - ha->flags.disable_risc_code_load = 0; - } else - ha->flags.disable_risc_code_load = - nv->cntr_flags_1.disable_loading_risc_code; - - if (ha->flags.disable_risc_code_load) { - dprintk(3, "qla1280_isp_firmware: Telling RISC to verify " - "checksum of loaded BIOS code.\n"); - - /* Verify checksum of loaded RISC code. */ - mb[0] = MBC_VERIFY_CHECKSUM; - /* mb[1] = ql12_risc_code_addr01; */ - mb[1] = *ql1280_board_tbl[ha->devnum].fwstart; - - if (!(status = - qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]))) { - /* Start firmware execution. */ - dprintk(3, "qla1280_isp_firmware: Startng F/W " - "execution.\n"); - - mb[0] = MBC_EXECUTE_FIRMWARE; - /* mb[1] = ql12_risc_code_addr01; */ - mb[1] = *ql1280_board_tbl[ha->devnum].fwstart; - qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]); - } else - printk(KERN_INFO "qla1280: RISC checksum failed.\n"); - } else { - dprintk(1, "qla1280: NVRAM configured to load RISC load.\n"); - status = 1; - } - - if (status) - dprintk(2, "qla1280_isp_firmware: **** Load RISC code ****\n"); - - LEAVE("qla1280_isp_firmware"); - return status; -} - /* * Chip diagnostics * Test chip for proper operation. @@ -2080,14 +2017,7 @@ qla1280_start_firmware(struct scsi_qla_host *ha) static int qla1280_load_firmware(struct scsi_qla_host *ha) { - int err = -ENODEV; - - /* If firmware needs to be loaded */ - if (!qla1280_isp_firmware(ha)) { - printk(KERN_ERR "scsi(%li): isp_firmware() failed!\n", - ha->host_no); - goto out; - } + int err; err = qla1280_chip_diag(ha); if (err) From 0888f4c3312847eec4814a6d7cdcaaaa9fbd3345 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 4 Jul 2005 17:48:55 +0200 Subject: [PATCH 021/114] [SCSI] qla1280: don't use bitfields for hardware access in isp_config Signed-off-by: Christoph Hellwig Signed-off-by: Thiemo Seufer Signed-off-by: James Bottomley --- drivers/scsi/qla1280.c | 44 ++++++++++++++++++++++++++++-------------- drivers/scsi/qla1280.h | 30 ++++++++++++---------------- 2 files changed, 41 insertions(+), 33 deletions(-) diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 9f975f7c1ea8..1a8b1147821d 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -2189,9 +2189,9 @@ qla1280_set_defaults(struct scsi_qla_host *ha) /* nv->cntr_flags_1.disable_loading_risc_code = 1; */ nv->firmware_feature.f.enable_fast_posting = 1; nv->firmware_feature.f.disable_synchronous_backoff = 1; - nv->termination.f.scsi_bus_0_control = 3; - nv->termination.f.scsi_bus_1_control = 3; - nv->termination.f.auto_term_support = 1; + nv->termination.scsi_bus_0_control = 3; + nv->termination.scsi_bus_1_control = 3; + nv->termination.auto_term_support = 1; /* * Set default FIFO magic - What appropriate values would be here @@ -2201,7 +2201,12 @@ qla1280_set_defaults(struct scsi_qla_host *ha) * header file provided by QLogic seems to be bogus or incomplete * at best. */ - nv->isp_config.c = ISP_CFG1_BENAB|ISP_CFG1_F128; + nv->isp_config.burst_enable = 1; + if (IS_ISP1040(ha)) + nv->isp_config.fifo_threshold |= 3; + else + nv->isp_config.fifo_threshold |= 4; + if (IS_ISP1x160(ha)) nv->isp_parameter = 0x01; /* fast memory enable */ @@ -2362,31 +2367,40 @@ qla1280_nvram_config(struct scsi_qla_host *ha) hwrev = RD_REG_WORD(®->cfg_0) & ISP_CFG0_HWMSK; - cfg1 = RD_REG_WORD(®->cfg_1); + cfg1 = RD_REG_WORD(®->cfg_1) & ~(BIT_4 | BIT_5 | BIT_6); cdma_conf = RD_REG_WORD(®->cdma_cfg); ddma_conf = RD_REG_WORD(®->ddma_cfg); /* Busted fifo, says mjacob. */ - if (hwrev == ISP_CFG0_1040A) - WRT_REG_WORD(®->cfg_1, cfg1 | ISP_CFG1_F64); - else - WRT_REG_WORD(®->cfg_1, cfg1 | ISP_CFG1_F64 | ISP_CFG1_BENAB); + if (hwrev != ISP_CFG0_1040A) + cfg1 |= nv->isp_config.fifo_threshold << 4; + + cfg1 |= nv->isp_config.burst_enable << 2; + WRT_REG_WORD(®->cfg_1, cfg1); WRT_REG_WORD(®->cdma_cfg, cdma_conf | CDMA_CONF_BENAB); WRT_REG_WORD(®->ddma_cfg, cdma_conf | DDMA_CONF_BENAB); } else { + uint16_t cfg1, term; + /* Set ISP hardware DMA burst */ - mb[0] = nv->isp_config.c; + cfg1 = nv->isp_config.fifo_threshold << 4; + cfg1 |= nv->isp_config.burst_enable << 2; /* Enable DMA arbitration on dual channel controllers */ if (ha->ports > 1) - mb[0] |= BIT_13; - WRT_REG_WORD(®->cfg_1, mb[0]); + cfg1 |= BIT_13; + WRT_REG_WORD(®->cfg_1, cfg1); /* Set SCSI termination. */ - WRT_REG_WORD(®->gpio_enable, (BIT_3 + BIT_2 + BIT_1 + BIT_0)); - mb[0] = nv->termination.c & (BIT_3 + BIT_2 + BIT_1 + BIT_0); - WRT_REG_WORD(®->gpio_data, mb[0]); + WRT_REG_WORD(®->gpio_enable, + BIT_7 | BIT_3 | BIT_2 | BIT_1 | BIT_0); + term = nv->termination.scsi_bus_1_control; + term |= nv->termination.scsi_bus_0_control << 2; + term |= nv->termination.auto_term_support << 7; + RD_REG_WORD(®->id_l); /* Flush PCI write */ + WRT_REG_WORD(®->gpio_data, term); } + RD_REG_WORD(®->id_l); /* Flush PCI write */ /* ISP parameter word. */ mb[0] = MBC_SET_SYSTEM_PARAMETER; diff --git a/drivers/scsi/qla1280.h b/drivers/scsi/qla1280.h index 18c20cf371af..4032ea3f2b94 100644 --- a/drivers/scsi/qla1280.h +++ b/drivers/scsi/qla1280.h @@ -375,29 +375,23 @@ struct nvram { uint16_t unused_12; /* 12, 13 */ uint16_t unused_14; /* 14, 15 */ - union { - uint8_t c; - struct { - uint8_t reserved:2; - uint8_t burst_enable:1; - uint8_t reserved_1:1; - uint8_t fifo_threshold:4; - } f; + struct { + uint8_t reserved:2; + uint8_t burst_enable:1; + uint8_t reserved_1:1; + uint8_t fifo_threshold:4; } isp_config; /* 16 */ /* Termination * 0 = Disable, 1 = high only, 3 = Auto term */ - union { - uint8_t c; - struct { - uint8_t scsi_bus_1_control:2; - uint8_t scsi_bus_0_control:2; - uint8_t unused_0:1; - uint8_t unused_1:1; - uint8_t unused_2:1; - uint8_t auto_term_support:1; - } f; + struct { + uint8_t scsi_bus_1_control:2; + uint8_t scsi_bus_0_control:2; + uint8_t unused_0:1; + uint8_t unused_1:1; + uint8_t unused_2:1; + uint8_t auto_term_support:1; } termination; /* 17 */ uint16_t isp_parameter; /* 18, 19 */ From 7a34766fdcec0c619aa68ace203b934dd7cf9dbc Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 4 Jul 2005 17:49:22 +0200 Subject: [PATCH 022/114] [SCSI] qla1280: don't use bitfields for hardware access, parameters Signed-off-by: Christoph Hellwig Signed-off-by: Thiemo Seufer Signed-off-by: James Bottomley --- drivers/scsi/qla1280.c | 143 +++++++++++++++++++++-------------------- drivers/scsi/qla1280.h | 21 +++--- 2 files changed, 81 insertions(+), 83 deletions(-) diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 1a8b1147821d..6481deb57048 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -1328,7 +1328,7 @@ qla1280_set_target_parameters(struct scsi_qla_host *ha, int bus, int target) uint8_t mr; uint16_t mb[MAILBOX_REGISTER_COUNT]; struct nvram *nv; - int status; + int status, lun; nv = &ha->nvram; @@ -1336,24 +1336,38 @@ qla1280_set_target_parameters(struct scsi_qla_host *ha, int bus, int target) /* Set Target Parameters. */ mb[0] = MBC_SET_TARGET_PARAMETERS; - mb[1] = (uint16_t) (bus ? target | BIT_7 : target); - mb[1] <<= 8; - - mb[2] = (nv->bus[bus].target[target].parameter.c << 8); + mb[1] = (uint16_t)((bus ? target | BIT_7 : target) << 8); + mb[2] = nv->bus[bus].target[target].parameter.renegotiate_on_error << 8; + mb[2] |= nv->bus[bus].target[target].parameter.stop_queue_on_check << 9; + mb[2] |= nv->bus[bus].target[target].parameter.auto_request_sense << 10; + mb[2] |= nv->bus[bus].target[target].parameter.tag_queuing << 11; + mb[2] |= nv->bus[bus].target[target].parameter.enable_sync << 12; + mb[2] |= nv->bus[bus].target[target].parameter.enable_wide << 13; + mb[2] |= nv->bus[bus].target[target].parameter.parity_checking << 14; + mb[2] |= nv->bus[bus].target[target].parameter.disconnect_allowed << 15; if (IS_ISP1x160(ha)) { mb[2] |= nv->bus[bus].target[target].ppr_1x160.flags.enable_ppr << 5; - mb[3] = (nv->bus[bus].target[target].flags.flags1x160.sync_offset << 8) | - nv->bus[bus].target[target].sync_period; + mb[3] = (nv->bus[bus].target[target].flags.flags1x160.sync_offset << 8); mb[6] = (nv->bus[bus].target[target].ppr_1x160.flags.ppr_options << 8) | nv->bus[bus].target[target].ppr_1x160.flags.ppr_bus_width; mr |= BIT_6; } else { - mb[3] = (nv->bus[bus].target[target].flags.flags1x80.sync_offset << 8) | - nv->bus[bus].target[target].sync_period; + mb[3] = (nv->bus[bus].target[target].flags.flags1x80.sync_offset << 8); } + mb[3] |= nv->bus[bus].target[target].sync_period; - status = qla1280_mailbox_command(ha, mr, &mb[0]); + status = qla1280_mailbox_command(ha, mr, mb); + + /* Set Device Queue Parameters. */ + for (lun = 0; lun < MAX_LUNS; lun++) { + mb[0] = MBC_SET_DEVICE_QUEUE; + mb[1] = (uint16_t)((bus ? target | BIT_7 : target) << 8); + mb[1] |= lun; + mb[2] = nv->bus[bus].max_queue_depth; + mb[3] = nv->bus[bus].target[target].execution_throttle; + status |= qla1280_mailbox_command(ha, 0x0f, mb); + } if (status) printk(KERN_WARNING "scsi(%ld:%i:%i): " @@ -1400,19 +1414,19 @@ qla1280_slave_configure(struct scsi_device *device) } #if LINUX_VERSION_CODE > 0x020500 - nv->bus[bus].target[target].parameter.f.enable_sync = device->sdtr; - nv->bus[bus].target[target].parameter.f.enable_wide = device->wdtr; + nv->bus[bus].target[target].parameter.enable_sync = device->sdtr; + nv->bus[bus].target[target].parameter.enable_wide = device->wdtr; nv->bus[bus].target[target].ppr_1x160.flags.enable_ppr = device->ppr; #endif if (driver_setup.no_sync || (driver_setup.sync_mask && (~driver_setup.sync_mask & (1 << target)))) - nv->bus[bus].target[target].parameter.f.enable_sync = 0; + nv->bus[bus].target[target].parameter.enable_sync = 0; if (driver_setup.no_wide || (driver_setup.wide_mask && (~driver_setup.wide_mask & (1 << target)))) - nv->bus[bus].target[target].parameter.f.enable_wide = 0; + nv->bus[bus].target[target].parameter.enable_wide = 0; if (IS_ISP1x160(ha)) { if (driver_setup.no_ppr || (driver_setup.ppr_mask && @@ -1421,7 +1435,7 @@ qla1280_slave_configure(struct scsi_device *device) } spin_lock_irqsave(HOST_LOCK, flags); - if (nv->bus[bus].target[target].parameter.f.enable_sync) + if (nv->bus[bus].target[target].parameter.enable_sync) status = qla1280_set_target_parameters(ha, bus, target); qla1280_get_target_parameters(ha, device); spin_unlock_irqrestore(HOST_LOCK, flags); @@ -2151,17 +2165,17 @@ qla1280_set_target_defaults(struct scsi_qla_host *ha, int bus, int target) { struct nvram *nv = &ha->nvram; - nv->bus[bus].target[target].parameter.f.renegotiate_on_error = 1; - nv->bus[bus].target[target].parameter.f.auto_request_sense = 1; - nv->bus[bus].target[target].parameter.f.tag_queuing = 1; - nv->bus[bus].target[target].parameter.f.enable_sync = 1; + nv->bus[bus].target[target].parameter.renegotiate_on_error = 1; + nv->bus[bus].target[target].parameter.auto_request_sense = 1; + nv->bus[bus].target[target].parameter.tag_queuing = 1; + nv->bus[bus].target[target].parameter.enable_sync = 1; #if 1 /* Some SCSI Processors do not seem to like this */ - nv->bus[bus].target[target].parameter.f.enable_wide = 1; + nv->bus[bus].target[target].parameter.enable_wide = 1; #endif - nv->bus[bus].target[target].parameter.f.parity_checking = 1; - nv->bus[bus].target[target].parameter.f.disconnect_allowed = 1; nv->bus[bus].target[target].execution_throttle = nv->bus[bus].max_queue_depth - 1; + nv->bus[bus].target[target].parameter.parity_checking = 1; + nv->bus[bus].target[target].parameter.disconnect_allowed = 1; if (IS_ISP1x160(ha)) { nv->bus[bus].target[target].flags.flags1x160.device_enable = 1; @@ -2237,66 +2251,53 @@ qla1280_config_target(struct scsi_qla_host *ha, int bus, int target) struct nvram *nv = &ha->nvram; uint16_t mb[MAILBOX_REGISTER_COUNT]; int status, lun; + uint16_t flag; /* Set Target Parameters. */ mb[0] = MBC_SET_TARGET_PARAMETERS; - mb[1] = (uint16_t) (bus ? target | BIT_7 : target); - mb[1] <<= 8; + mb[1] = (uint16_t)((bus ? target | BIT_7 : target) << 8); /* - * Do not enable wide, sync, and ppr for the initial - * INQUIRY run. We enable this later if we determine - * the target actually supports it. + * Do not enable sync and ppr for the initial INQUIRY run. We + * enable this later if we determine the target actually + * supports it. */ - nv->bus[bus].target[target].parameter.f. - auto_request_sense = 1; - nv->bus[bus].target[target].parameter.f. - stop_queue_on_check = 0; - - if (IS_ISP1x160(ha)) - nv->bus[bus].target[target].ppr_1x160. - flags.enable_ppr = 0; - - /* - * No sync, wide, etc. while probing - */ - mb[2] = (nv->bus[bus].target[target].parameter.c << 8) & - ~(TP_SYNC /*| TP_WIDE | TP_PPR*/); + mb[2] = (TP_RENEGOTIATE | TP_AUTO_REQUEST_SENSE | TP_TAGGED_QUEUE + | TP_WIDE | TP_PARITY | TP_DISCONNECT); if (IS_ISP1x160(ha)) mb[3] = nv->bus[bus].target[target].flags.flags1x160.sync_offset << 8; else mb[3] = nv->bus[bus].target[target].flags.flags1x80.sync_offset << 8; mb[3] |= nv->bus[bus].target[target].sync_period; - - status = qla1280_mailbox_command(ha, BIT_3 | BIT_2 | BIT_1 | BIT_0, &mb[0]); + status = qla1280_mailbox_command(ha, 0x0f, mb); /* Save Tag queuing enable flag. */ - mb[0] = BIT_0 << target; - if (nv->bus[bus].target[target].parameter.f.tag_queuing) - ha->bus_settings[bus].qtag_enables |= mb[0]; + flag = (BIT_0 << target) & mb[0]; + if (nv->bus[bus].target[target].parameter.tag_queuing) + ha->bus_settings[bus].qtag_enables |= flag; /* Save Device enable flag. */ if (IS_ISP1x160(ha)) { if (nv->bus[bus].target[target].flags.flags1x160.device_enable) - ha->bus_settings[bus].device_enables |= mb[0]; + ha->bus_settings[bus].device_enables |= flag; ha->bus_settings[bus].lun_disables |= 0; } else { if (nv->bus[bus].target[target].flags.flags1x80.device_enable) - ha->bus_settings[bus].device_enables |= mb[0]; + ha->bus_settings[bus].device_enables |= flag; /* Save LUN disable flag. */ if (nv->bus[bus].target[target].flags.flags1x80.lun_disable) - ha->bus_settings[bus].lun_disables |= mb[0]; + ha->bus_settings[bus].lun_disables |= flag; } /* Set Device Queue Parameters. */ for (lun = 0; lun < MAX_LUNS; lun++) { mb[0] = MBC_SET_DEVICE_QUEUE; - mb[1] = (uint16_t)(bus ? target | BIT_7 : target); - mb[1] = mb[1] << 8 | lun; + mb[1] = (uint16_t)((bus ? target | BIT_7 : target) << 8); + mb[1] |= lun; mb[2] = nv->bus[bus].max_queue_depth; mb[3] = nv->bus[bus].target[target].execution_throttle; - status |= qla1280_mailbox_command(ha, 0x0f, &mb[0]); + status |= qla1280_mailbox_command(ha, 0x0f, mb); } return status; @@ -2341,7 +2342,6 @@ qla1280_nvram_config(struct scsi_qla_host *ha) struct nvram *nv = &ha->nvram; int bus, target, status = 0; uint16_t mb[MAILBOX_REGISTER_COUNT]; - uint16_t mask; ENTER("qla1280_nvram_config"); @@ -2349,7 +2349,7 @@ qla1280_nvram_config(struct scsi_qla_host *ha) /* Always force AUTO sense for LINUX SCSI */ for (bus = 0; bus < MAX_BUSES; bus++) for (target = 0; target < MAX_TARGETS; target++) { - nv->bus[bus].target[target].parameter.f. + nv->bus[bus].target[target].parameter. auto_request_sense = 1; } } else { @@ -2416,16 +2416,17 @@ qla1280_nvram_config(struct scsi_qla_host *ha) /* Firmware feature word. */ mb[0] = MBC_SET_FIRMWARE_FEATURES; - mask = BIT_5 | BIT_1 | BIT_0; - mb[1] = le16_to_cpu(nv->firmware_feature.w) & (mask); + mb[1] = nv->firmware_feature.f.enable_fast_posting; + mb[1] |= nv->firmware_feature.f.report_lvd_bus_transition << 1; + mb[1] |= nv->firmware_feature.f.disable_synchronous_backoff << 5; #if defined(CONFIG_IA64_GENERIC) || defined (CONFIG_IA64_SGI_SN2) if (ia64_platform_is("sn2")) { printk(KERN_INFO "scsi(%li): Enabling SN2 PCI DMA " "workaround\n", ha->host_no); - mb[1] |= BIT_9; + mb[1] |= nv->firmware_feature.f.unused_9 << 9; /* XXX */ } #endif - status |= qla1280_mailbox_command(ha, mask, &mb[0]); + status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, mb); /* Retry count and delay. */ mb[0] = MBC_SET_RETRY_COUNT; @@ -2454,27 +2455,27 @@ qla1280_nvram_config(struct scsi_qla_host *ha) mb[2] |= BIT_5; if (nv->bus[1].config_2.data_line_active_negation) mb[2] |= BIT_4; - status |= qla1280_mailbox_command(ha, BIT_2 | BIT_1 | BIT_0, &mb[0]); + status |= qla1280_mailbox_command(ha, BIT_2 | BIT_1 | BIT_0, mb); mb[0] = MBC_SET_DATA_OVERRUN_RECOVERY; mb[1] = 2; /* Reset SCSI bus and return all outstanding IO */ - status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]); + status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, mb); /* thingy */ mb[0] = MBC_SET_PCI_CONTROL; - mb[1] = 2; /* Data DMA Channel Burst Enable */ - mb[2] = 2; /* Command DMA Channel Burst Enable */ - status |= qla1280_mailbox_command(ha, BIT_2 | BIT_1 | BIT_0, &mb[0]); + mb[1] = BIT_1; /* Data DMA Channel Burst Enable */ + mb[2] = BIT_1; /* Command DMA Channel Burst Enable */ + status |= qla1280_mailbox_command(ha, BIT_2 | BIT_1 | BIT_0, mb); mb[0] = MBC_SET_TAG_AGE_LIMIT; mb[1] = 8; - status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]); + status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, mb); /* Selection timeout. */ mb[0] = MBC_SET_SELECTION_TIMEOUT; mb[1] = nv->bus[0].selection_timeout; mb[2] = nv->bus[1].selection_timeout; - status |= qla1280_mailbox_command(ha, BIT_2 | BIT_1 | BIT_0, &mb[0]); + status |= qla1280_mailbox_command(ha, BIT_2 | BIT_1 | BIT_0, mb); for (bus = 0; bus < ha->ports; bus++) status |= qla1280_config_bus(ha, bus); @@ -3915,21 +3916,21 @@ qla1280_get_target_options(struct scsi_cmnd *cmd, struct scsi_qla_host *ha) result = cmd->request_buffer; n = &ha->nvram; - n->bus[bus].target[target].parameter.f.enable_wide = 0; - n->bus[bus].target[target].parameter.f.enable_sync = 0; + n->bus[bus].target[target].parameter.enable_wide = 0; + n->bus[bus].target[target].parameter.enable_sync = 0; n->bus[bus].target[target].ppr_1x160.flags.enable_ppr = 0; if (result[7] & 0x60) - n->bus[bus].target[target].parameter.f.enable_wide = 1; + n->bus[bus].target[target].parameter.enable_wide = 1; if (result[7] & 0x10) - n->bus[bus].target[target].parameter.f.enable_sync = 1; + n->bus[bus].target[target].parameter.enable_sync = 1; if ((result[2] >= 3) && (result[4] + 5 > 56) && (result[56] & 0x4)) n->bus[bus].target[target].ppr_1x160.flags.enable_ppr = 1; dprintk(2, "get_target_options(): wide %i, sync %i, ppr %i\n", - n->bus[bus].target[target].parameter.f.enable_wide, - n->bus[bus].target[target].parameter.f.enable_sync, + n->bus[bus].target[target].parameter.enable_wide, + n->bus[bus].target[target].parameter.enable_sync, n->bus[bus].target[target].ppr_1x160.flags.enable_ppr); } #endif diff --git a/drivers/scsi/qla1280.h b/drivers/scsi/qla1280.h index 4032ea3f2b94..7c919db97a40 100644 --- a/drivers/scsi/qla1280.h +++ b/drivers/scsi/qla1280.h @@ -451,18 +451,15 @@ struct nvram { uint16_t unused_38; /* 38, 39 */ struct { - union { - uint8_t c; - struct { - uint8_t renegotiate_on_error:1; - uint8_t stop_queue_on_check:1; - uint8_t auto_request_sense:1; - uint8_t tag_queuing:1; - uint8_t enable_sync:1; - uint8_t enable_wide:1; - uint8_t parity_checking:1; - uint8_t disconnect_allowed:1; - } f; + struct { + uint8_t renegotiate_on_error:1; + uint8_t stop_queue_on_check:1; + uint8_t auto_request_sense:1; + uint8_t tag_queuing:1; + uint8_t enable_sync:1; + uint8_t enable_wide:1; + uint8_t parity_checking:1; + uint8_t disconnect_allowed:1; } parameter; /* 40 */ uint8_t execution_throttle; /* 41 */ From 8d6810d33e5e43b11675190318a81303c601a568 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 4 Jul 2005 17:49:26 +0200 Subject: [PATCH 023/114] [SCSI] qla1280: endianess annotations Signed-off-by: Christoph Hellwig Signed-off-by: James Bottomley --- drivers/scsi/qla1280.c | 8 +- drivers/scsi/qla1280.h | 270 ++++++++++++++++++++--------------------- 2 files changed, 139 insertions(+), 139 deletions(-) diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c index 6481deb57048..637fb6565d28 100644 --- a/drivers/scsi/qla1280.c +++ b/drivers/scsi/qla1280.c @@ -1546,7 +1546,7 @@ qla1280_return_status(struct response * sts, struct scsi_cmnd *cp) int host_status = DID_ERROR; uint16_t comp_status = le16_to_cpu(sts->comp_status); uint16_t state_flags = le16_to_cpu(sts->state_flags); - uint16_t residual_length = le16_to_cpu(sts->residual_length); + uint16_t residual_length = le32_to_cpu(sts->residual_length); uint16_t scsi_status = le16_to_cpu(sts->scsi_status); #if DEBUG_QLA1280_INTR static char *reason[] = { @@ -1932,7 +1932,7 @@ qla1280_load_firmware_dma(struct scsi_qla_host *ha) "%d,%d(0x%x)\n", risc_code_address, cnt, num, risc_address); for(i = 0; i < cnt; i++) - ((uint16_t *)ha->request_ring)[i] = + ((__le16 *)ha->request_ring)[i] = cpu_to_le16(risc_code_address[i]); mb[0] = MBC_LOAD_RAM; @@ -2986,7 +2986,7 @@ qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) struct scsi_cmnd *cmd = sp->cmd; cmd_a64_entry_t *pkt; struct scatterlist *sg = NULL; - u32 *dword_ptr; + __le32 *dword_ptr; dma_addr_t dma_handle; int status = 0; int cnt; @@ -3273,7 +3273,7 @@ qla1280_32bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp) struct scsi_cmnd *cmd = sp->cmd; struct cmd_entry *pkt; struct scatterlist *sg = NULL; - uint32_t *dword_ptr; + __le32 *dword_ptr; int status = 0; int cnt; int req_cnt; diff --git a/drivers/scsi/qla1280.h b/drivers/scsi/qla1280.h index 7c919db97a40..59915fb70301 100644 --- a/drivers/scsi/qla1280.h +++ b/drivers/scsi/qla1280.h @@ -516,23 +516,23 @@ struct cmd_entry { uint8_t entry_count; /* Entry count. */ uint8_t sys_define; /* System defined. */ uint8_t entry_status; /* Entry Status. */ - uint32_t handle; /* System handle. */ + __le32 handle; /* System handle. */ uint8_t lun; /* SCSI LUN */ uint8_t target; /* SCSI ID */ - uint16_t cdb_len; /* SCSI command length. */ - uint16_t control_flags; /* Control flags. */ - uint16_t reserved; - uint16_t timeout; /* Command timeout. */ - uint16_t dseg_count; /* Data segment count. */ + __le16 cdb_len; /* SCSI command length. */ + __le16 control_flags; /* Control flags. */ + __le16 reserved; + __le16 timeout; /* Command timeout. */ + __le16 dseg_count; /* Data segment count. */ uint8_t scsi_cdb[MAX_CMDSZ]; /* SCSI command words. */ - uint32_t dseg_0_address; /* Data segment 0 address. */ - uint32_t dseg_0_length; /* Data segment 0 length. */ - uint32_t dseg_1_address; /* Data segment 1 address. */ - uint32_t dseg_1_length; /* Data segment 1 length. */ - uint32_t dseg_2_address; /* Data segment 2 address. */ - uint32_t dseg_2_length; /* Data segment 2 length. */ - uint32_t dseg_3_address; /* Data segment 3 address. */ - uint32_t dseg_3_length; /* Data segment 3 length. */ + __le32 dseg_0_address; /* Data segment 0 address. */ + __le32 dseg_0_length; /* Data segment 0 length. */ + __le32 dseg_1_address; /* Data segment 1 address. */ + __le32 dseg_1_length; /* Data segment 1 length. */ + __le32 dseg_2_address; /* Data segment 2 address. */ + __le32 dseg_2_length; /* Data segment 2 length. */ + __le32 dseg_3_address; /* Data segment 3 address. */ + __le32 dseg_3_length; /* Data segment 3 length. */ }; /* @@ -544,21 +544,21 @@ struct cont_entry { uint8_t entry_count; /* Entry count. */ uint8_t sys_define; /* System defined. */ uint8_t entry_status; /* Entry Status. */ - uint32_t reserved; /* Reserved */ - uint32_t dseg_0_address; /* Data segment 0 address. */ - uint32_t dseg_0_length; /* Data segment 0 length. */ - uint32_t dseg_1_address; /* Data segment 1 address. */ - uint32_t dseg_1_length; /* Data segment 1 length. */ - uint32_t dseg_2_address; /* Data segment 2 address. */ - uint32_t dseg_2_length; /* Data segment 2 length. */ - uint32_t dseg_3_address; /* Data segment 3 address. */ - uint32_t dseg_3_length; /* Data segment 3 length. */ - uint32_t dseg_4_address; /* Data segment 4 address. */ - uint32_t dseg_4_length; /* Data segment 4 length. */ - uint32_t dseg_5_address; /* Data segment 5 address. */ - uint32_t dseg_5_length; /* Data segment 5 length. */ - uint32_t dseg_6_address; /* Data segment 6 address. */ - uint32_t dseg_6_length; /* Data segment 6 length. */ + __le32 reserved; /* Reserved */ + __le32 dseg_0_address; /* Data segment 0 address. */ + __le32 dseg_0_length; /* Data segment 0 length. */ + __le32 dseg_1_address; /* Data segment 1 address. */ + __le32 dseg_1_length; /* Data segment 1 length. */ + __le32 dseg_2_address; /* Data segment 2 address. */ + __le32 dseg_2_length; /* Data segment 2 length. */ + __le32 dseg_3_address; /* Data segment 3 address. */ + __le32 dseg_3_length; /* Data segment 3 length. */ + __le32 dseg_4_address; /* Data segment 4 address. */ + __le32 dseg_4_length; /* Data segment 4 length. */ + __le32 dseg_5_address; /* Data segment 5 address. */ + __le32 dseg_5_length; /* Data segment 5 length. */ + __le32 dseg_6_address; /* Data segment 6 address. */ + __le32 dseg_6_length; /* Data segment 6 length. */ }; /* @@ -574,22 +574,22 @@ struct response { #define RF_FULL BIT_1 /* Full */ #define RF_BAD_HEADER BIT_2 /* Bad header. */ #define RF_BAD_PAYLOAD BIT_3 /* Bad payload. */ - uint32_t handle; /* System handle. */ - uint16_t scsi_status; /* SCSI status. */ - uint16_t comp_status; /* Completion status. */ - uint16_t state_flags; /* State flags. */ -#define SF_TRANSFER_CMPL BIT_14 /* Transfer Complete. */ -#define SF_GOT_SENSE BIT_13 /* Got Sense */ -#define SF_GOT_STATUS BIT_12 /* Got Status */ -#define SF_TRANSFERRED_DATA BIT_11 /* Transferred data */ -#define SF_SENT_CDB BIT_10 /* Send CDB */ -#define SF_GOT_TARGET BIT_9 /* */ -#define SF_GOT_BUS BIT_8 /* */ - uint16_t status_flags; /* Status flags. */ - uint16_t time; /* Time. */ - uint16_t req_sense_length; /* Request sense data length. */ - uint32_t residual_length; /* Residual transfer length. */ - uint16_t reserved[4]; + __le32 handle; /* System handle. */ + __le16 scsi_status; /* SCSI status. */ + __le16 comp_status; /* Completion status. */ + __le16 state_flags; /* State flags. */ +#define SF_TRANSFER_CMPL BIT_14 /* Transfer Complete. */ +#define SF_GOT_SENSE BIT_13 /* Got Sense */ +#define SF_GOT_STATUS BIT_12 /* Got Status */ +#define SF_TRANSFERRED_DATA BIT_11 /* Transferred data */ +#define SF_SENT_CDB BIT_10 /* Send CDB */ +#define SF_GOT_TARGET BIT_9 /* */ +#define SF_GOT_BUS BIT_8 /* */ + __le16 status_flags; /* Status flags. */ + __le16 time; /* Time. */ + __le16 req_sense_length;/* Request sense data length. */ + __le32 residual_length; /* Residual transfer length. */ + __le16 reserved[4]; uint8_t req_sense_data[32]; /* Request sense data. */ }; @@ -602,7 +602,7 @@ struct mrk_entry { uint8_t entry_count; /* Entry count. */ uint8_t sys_define; /* System defined. */ uint8_t entry_status; /* Entry Status. */ - uint32_t reserved; + __le32 reserved; uint8_t lun; /* SCSI LUN */ uint8_t target; /* SCSI ID */ uint8_t modifier; /* Modifier (7-0). */ @@ -626,11 +626,11 @@ struct ecmd_entry { uint32_t handle; /* System handle. */ uint8_t lun; /* SCSI LUN */ uint8_t target; /* SCSI ID */ - uint16_t cdb_len; /* SCSI command length. */ - uint16_t control_flags; /* Control flags. */ - uint16_t reserved; - uint16_t timeout; /* Command timeout. */ - uint16_t dseg_count; /* Data segment count. */ + __le16 cdb_len; /* SCSI command length. */ + __le16 control_flags; /* Control flags. */ + __le16 reserved; + __le16 timeout; /* Command timeout. */ + __le16 dseg_count; /* Data segment count. */ uint8_t scsi_cdb[88]; /* SCSI command words. */ }; @@ -643,20 +643,20 @@ typedef struct { uint8_t entry_count; /* Entry count. */ uint8_t sys_define; /* System defined. */ uint8_t entry_status; /* Entry Status. */ - uint32_t handle; /* System handle. */ + __le32 handle; /* System handle. */ uint8_t lun; /* SCSI LUN */ uint8_t target; /* SCSI ID */ - uint16_t cdb_len; /* SCSI command length. */ - uint16_t control_flags; /* Control flags. */ - uint16_t reserved; - uint16_t timeout; /* Command timeout. */ - uint16_t dseg_count; /* Data segment count. */ + __le16 cdb_len; /* SCSI command length. */ + __le16 control_flags; /* Control flags. */ + __le16 reserved; + __le16 timeout; /* Command timeout. */ + __le16 dseg_count; /* Data segment count. */ uint8_t scsi_cdb[MAX_CMDSZ]; /* SCSI command words. */ - uint32_t reserved_1[2]; /* unused */ - uint32_t dseg_0_address[2]; /* Data segment 0 address. */ - uint32_t dseg_0_length; /* Data segment 0 length. */ - uint32_t dseg_1_address[2]; /* Data segment 1 address. */ - uint32_t dseg_1_length; /* Data segment 1 length. */ + __le32 reserved_1[2]; /* unused */ + __le32 dseg_0_address[2]; /* Data segment 0 address. */ + __le32 dseg_0_length; /* Data segment 0 length. */ + __le32 dseg_1_address[2]; /* Data segment 1 address. */ + __le32 dseg_1_length; /* Data segment 1 length. */ } cmd_a64_entry_t, request_t; /* @@ -668,16 +668,16 @@ struct cont_a64_entry { uint8_t entry_count; /* Entry count. */ uint8_t sys_define; /* System defined. */ uint8_t entry_status; /* Entry Status. */ - uint32_t dseg_0_address[2]; /* Data segment 0 address. */ - uint32_t dseg_0_length; /* Data segment 0 length. */ - uint32_t dseg_1_address[2]; /* Data segment 1 address. */ - uint32_t dseg_1_length; /* Data segment 1 length. */ - uint32_t dseg_2_address[2]; /* Data segment 2 address. */ - uint32_t dseg_2_length; /* Data segment 2 length. */ - uint32_t dseg_3_address[2]; /* Data segment 3 address. */ - uint32_t dseg_3_length; /* Data segment 3 length. */ - uint32_t dseg_4_address[2]; /* Data segment 4 address. */ - uint32_t dseg_4_length; /* Data segment 4 length. */ + __le32 dseg_0_address[2]; /* Data segment 0 address. */ + __le32 dseg_0_length; /* Data segment 0 length. */ + __le32 dseg_1_address[2]; /* Data segment 1 address. */ + __le32 dseg_1_length; /* Data segment 1 length. */ + __le32 dseg_2_address[2]; /* Data segment 2 address. */ + __le32 dseg_2_length; /* Data segment 2 length. */ + __le32 dseg_3_address[2]; /* Data segment 3 address. */ + __le32 dseg_3_length; /* Data segment 3 length. */ + __le32 dseg_4_address[2]; /* Data segment 4 address. */ + __le32 dseg_4_length; /* Data segment 4 length. */ }; /* @@ -689,10 +689,10 @@ struct elun_entry { uint8_t entry_count; /* Entry count. */ uint8_t reserved_1; uint8_t entry_status; /* Entry Status not used. */ - uint32_t reserved_2; - uint16_t lun; /* Bit 15 is bus number. */ - uint16_t reserved_4; - uint32_t option_flags; + __le32 reserved_2; + __le16 lun; /* Bit 15 is bus number. */ + __le16 reserved_4; + __le32 option_flags; uint8_t status; uint8_t reserved_5; uint8_t command_count; /* Number of ATIOs allocated. */ @@ -702,8 +702,8 @@ struct elun_entry { /* commands (2-26). */ uint8_t group_7_length; /* SCSI CDB length for group 7 */ /* commands (2-26). */ - uint16_t timeout; /* 0 = 30 seconds, 0xFFFF = disable */ - uint16_t reserved_6[20]; + __le16 timeout; /* 0 = 30 seconds, 0xFFFF = disable */ + __le16 reserved_6[20]; }; /* @@ -717,20 +717,20 @@ struct modify_lun_entry { uint8_t entry_count; /* Entry count. */ uint8_t reserved_1; uint8_t entry_status; /* Entry Status. */ - uint32_t reserved_2; + __le32 reserved_2; uint8_t lun; /* SCSI LUN */ uint8_t reserved_3; uint8_t operators; uint8_t reserved_4; - uint32_t option_flags; + __le32 option_flags; uint8_t status; uint8_t reserved_5; uint8_t command_count; /* Number of ATIOs allocated. */ uint8_t immed_notify_count; /* Number of Immediate Notify */ /* entries allocated. */ - uint16_t reserved_6; - uint16_t timeout; /* 0 = 30 seconds, 0xFFFF = disable */ - uint16_t reserved_7[20]; + __le16 reserved_6; + __le16 timeout; /* 0 = 30 seconds, 0xFFFF = disable */ + __le16 reserved_7[20]; }; /* @@ -742,20 +742,20 @@ struct notify_entry { uint8_t entry_count; /* Entry count. */ uint8_t reserved_1; uint8_t entry_status; /* Entry Status. */ - uint32_t reserved_2; + __le32 reserved_2; uint8_t lun; uint8_t initiator_id; uint8_t reserved_3; uint8_t target_id; - uint32_t option_flags; + __le32 option_flags; uint8_t status; uint8_t reserved_4; uint8_t tag_value; /* Received queue tag message value */ uint8_t tag_type; /* Received queue tag message type */ /* entries allocated. */ - uint16_t seq_id; + __le16 seq_id; uint8_t scsi_msg[8]; /* SCSI message not handled by ISP */ - uint16_t reserved_5[8]; + __le16 reserved_5[8]; uint8_t sense_data[18]; }; @@ -768,16 +768,16 @@ struct nack_entry { uint8_t entry_count; /* Entry count. */ uint8_t reserved_1; uint8_t entry_status; /* Entry Status. */ - uint32_t reserved_2; + __le32 reserved_2; uint8_t lun; uint8_t initiator_id; uint8_t reserved_3; uint8_t target_id; - uint32_t option_flags; + __le32 option_flags; uint8_t status; uint8_t event; - uint16_t seq_id; - uint16_t reserved_4[22]; + __le16 seq_id; + __le16 reserved_4[22]; }; /* @@ -789,12 +789,12 @@ struct atio_entry { uint8_t entry_count; /* Entry count. */ uint8_t reserved_1; uint8_t entry_status; /* Entry Status. */ - uint32_t reserved_2; + __le32 reserved_2; uint8_t lun; uint8_t initiator_id; uint8_t cdb_len; uint8_t target_id; - uint32_t option_flags; + __le32 option_flags; uint8_t status; uint8_t scsi_status; uint8_t tag_value; /* Received queue tag message value */ @@ -812,28 +812,28 @@ struct ctio_entry { uint8_t entry_count; /* Entry count. */ uint8_t reserved_1; uint8_t entry_status; /* Entry Status. */ - uint32_t reserved_2; + __le32 reserved_2; uint8_t lun; /* SCSI LUN */ uint8_t initiator_id; uint8_t reserved_3; uint8_t target_id; - uint32_t option_flags; + __le32 option_flags; uint8_t status; uint8_t scsi_status; uint8_t tag_value; /* Received queue tag message value */ uint8_t tag_type; /* Received queue tag message type */ - uint32_t transfer_length; - uint32_t residual; - uint16_t timeout; /* 0 = 30 seconds, 0xFFFF = disable */ - uint16_t dseg_count; /* Data segment count. */ - uint32_t dseg_0_address; /* Data segment 0 address. */ - uint32_t dseg_0_length; /* Data segment 0 length. */ - uint32_t dseg_1_address; /* Data segment 1 address. */ - uint32_t dseg_1_length; /* Data segment 1 length. */ - uint32_t dseg_2_address; /* Data segment 2 address. */ - uint32_t dseg_2_length; /* Data segment 2 length. */ - uint32_t dseg_3_address; /* Data segment 3 address. */ - uint32_t dseg_3_length; /* Data segment 3 length. */ + __le32 transfer_length; + __le32 residual; + __le16 timeout; /* 0 = 30 seconds, 0xFFFF = disable */ + __le16 dseg_count; /* Data segment count. */ + __le32 dseg_0_address; /* Data segment 0 address. */ + __le32 dseg_0_length; /* Data segment 0 length. */ + __le32 dseg_1_address; /* Data segment 1 address. */ + __le32 dseg_1_length; /* Data segment 1 length. */ + __le32 dseg_2_address; /* Data segment 2 address. */ + __le32 dseg_2_length; /* Data segment 2 length. */ + __le32 dseg_3_address; /* Data segment 3 address. */ + __le32 dseg_3_length; /* Data segment 3 length. */ }; /* @@ -845,24 +845,24 @@ struct ctio_ret_entry { uint8_t entry_count; /* Entry count. */ uint8_t reserved_1; uint8_t entry_status; /* Entry Status. */ - uint32_t reserved_2; + __le32 reserved_2; uint8_t lun; /* SCSI LUN */ uint8_t initiator_id; uint8_t reserved_3; uint8_t target_id; - uint32_t option_flags; + __le32 option_flags; uint8_t status; uint8_t scsi_status; uint8_t tag_value; /* Received queue tag message value */ uint8_t tag_type; /* Received queue tag message type */ - uint32_t transfer_length; - uint32_t residual; - uint16_t timeout; /* 0 = 30 seconds, 0xFFFF = disable */ - uint16_t dseg_count; /* Data segment count. */ - uint32_t dseg_0_address; /* Data segment 0 address. */ - uint32_t dseg_0_length; /* Data segment 0 length. */ - uint32_t dseg_1_address; /* Data segment 1 address. */ - uint16_t dseg_1_length; /* Data segment 1 length. */ + __le32 transfer_length; + __le32 residual; + __le16 timeout; /* 0 = 30 seconds, 0xFFFF = disable */ + __le16 dseg_count; /* Data segment count. */ + __le32 dseg_0_address; /* Data segment 0 address. */ + __le32 dseg_0_length; /* Data segment 0 length. */ + __le32 dseg_1_address; /* Data segment 1 address. */ + __le16 dseg_1_length; /* Data segment 1 length. */ uint8_t sense_data[18]; }; @@ -875,25 +875,25 @@ struct ctio_a64_entry { uint8_t entry_count; /* Entry count. */ uint8_t reserved_1; uint8_t entry_status; /* Entry Status. */ - uint32_t reserved_2; + __le32 reserved_2; uint8_t lun; /* SCSI LUN */ uint8_t initiator_id; uint8_t reserved_3; uint8_t target_id; - uint32_t option_flags; + __le32 option_flags; uint8_t status; uint8_t scsi_status; uint8_t tag_value; /* Received queue tag message value */ uint8_t tag_type; /* Received queue tag message type */ - uint32_t transfer_length; - uint32_t residual; - uint16_t timeout; /* 0 = 30 seconds, 0xFFFF = disable */ - uint16_t dseg_count; /* Data segment count. */ - uint32_t reserved_4[2]; - uint32_t dseg_0_address[2]; /* Data segment 0 address. */ - uint32_t dseg_0_length; /* Data segment 0 length. */ - uint32_t dseg_1_address[2]; /* Data segment 1 address. */ - uint32_t dseg_1_length; /* Data segment 1 length. */ + __le32 transfer_length; + __le32 residual; + __le16 timeout; /* 0 = 30 seconds, 0xFFFF = disable */ + __le16 dseg_count; /* Data segment count. */ + __le32 reserved_4[2]; + __le32 dseg_0_address[2];/* Data segment 0 address. */ + __le32 dseg_0_length; /* Data segment 0 length. */ + __le32 dseg_1_address[2];/* Data segment 1 address. */ + __le32 dseg_1_length; /* Data segment 1 length. */ }; /* @@ -905,21 +905,21 @@ struct ctio_a64_ret_entry { uint8_t entry_count; /* Entry count. */ uint8_t reserved_1; uint8_t entry_status; /* Entry Status. */ - uint32_t reserved_2; + __le32 reserved_2; uint8_t lun; /* SCSI LUN */ uint8_t initiator_id; uint8_t reserved_3; uint8_t target_id; - uint32_t option_flags; + __le32 option_flags; uint8_t status; uint8_t scsi_status; uint8_t tag_value; /* Received queue tag message value */ uint8_t tag_type; /* Received queue tag message type */ - uint32_t transfer_length; - uint32_t residual; - uint16_t timeout; /* 0 = 30 seconds, 0xFFFF = disable */ - uint16_t dseg_count; /* Data segment count. */ - uint16_t reserved_4[7]; + __le32 transfer_length; + __le32 residual; + __le16 timeout; /* 0 = 30 seconds, 0xFFFF = disable */ + __le16 dseg_count; /* Data segment count. */ + __le16 reserved_4[7]; uint8_t sense_data[18]; }; From 60a13213840296b1e32d6781653a0eaa83d04382 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Fri, 22 Jul 2005 16:42:28 +0200 Subject: [PATCH 024/114] [SCSI] aic79xx: Remove busyq From: Jeff Garzik This patch removes the busyq in aic79xx and uses the command-queue from the midlayer instead. Additionally some dead code is removed. Signed-off-by: Hannes Reinecke Fixed rejections Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic79xx_core.c | 1 - drivers/scsi/aic7xxx/aic79xx_osm.c | 854 +++++----------------------- drivers/scsi/aic7xxx/aic79xx_osm.h | 26 +- drivers/scsi/aic7xxx/aic79xx_proc.c | 12 - 4 files changed, 154 insertions(+), 739 deletions(-) diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c index 137fb1a37dd1..d69bbffb34a0 100644 --- a/drivers/scsi/aic7xxx/aic79xx_core.c +++ b/drivers/scsi/aic7xxx/aic79xx_core.c @@ -9039,7 +9039,6 @@ ahd_dump_card_state(struct ahd_softc *ahd) ahd_outb(ahd, STACK, (ahd->saved_stack[i] >> 8) & 0xFF); } printf("\n<<<<<<<<<<<<<<<<< Dump Card State Ends >>>>>>>>>>>>>>>>>>\n"); - ahd_platform_dump_card_state(ahd); ahd_restore_modes(ahd, saved_modes); if (paused == 0) ahd_unpause(ahd); diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index 329cb2331339..7463dd515d11 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -53,11 +53,6 @@ #include "aiclib.c" #include /* __setup */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) -#include "sd.h" /* For geometry detection */ -#endif - #include /* For fetching system memory size */ #include /* For ssleep/msleep */ @@ -66,11 +61,6 @@ */ spinlock_t ahd_list_spinlock; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) -/* For dynamic sglist size calculation. */ -u_int ahd_linux_nseg; -#endif - /* * Bucket size for counting good commands in between bad ones. */ @@ -457,7 +447,6 @@ static void ahd_linux_filter_inquiry(struct ahd_softc *ahd, static void ahd_linux_dev_timed_unfreeze(u_long arg); static void ahd_linux_sem_timeout(u_long arg); static void ahd_linux_initialize_scsi_bus(struct ahd_softc *ahd); -static void ahd_linux_size_nseg(void); static void ahd_linux_thread_run_complete_queue(struct ahd_softc *ahd); static void ahd_linux_start_dv(struct ahd_softc *ahd); static void ahd_linux_dv_timeout(struct scsi_cmnd *cmd); @@ -516,31 +505,23 @@ static struct ahd_linux_device* ahd_linux_alloc_device(struct ahd_softc*, u_int); static void ahd_linux_free_device(struct ahd_softc*, struct ahd_linux_device*); -static void ahd_linux_run_device_queue(struct ahd_softc*, - struct ahd_linux_device*); +static int ahd_linux_run_command(struct ahd_softc*, + struct ahd_linux_device*, + struct scsi_cmnd *); static void ahd_linux_setup_tag_info_global(char *p); static aic_option_callback_t ahd_linux_setup_tag_info; static aic_option_callback_t ahd_linux_setup_rd_strm_info; static aic_option_callback_t ahd_linux_setup_dv; static aic_option_callback_t ahd_linux_setup_iocell_info; static int ahd_linux_next_unit(void); -static void ahd_runq_tasklet(unsigned long data); static int aic79xx_setup(char *c); /****************************** Inlines ***************************************/ static __inline void ahd_schedule_completeq(struct ahd_softc *ahd); -static __inline void ahd_schedule_runq(struct ahd_softc *ahd); -static __inline void ahd_setup_runq_tasklet(struct ahd_softc *ahd); -static __inline void ahd_teardown_runq_tasklet(struct ahd_softc *ahd); static __inline struct ahd_linux_device* ahd_linux_get_device(struct ahd_softc *ahd, u_int channel, u_int target, u_int lun, int alloc); static struct ahd_cmd *ahd_linux_run_complete_queue(struct ahd_softc *ahd); -static __inline void ahd_linux_check_device_queue(struct ahd_softc *ahd, - struct ahd_linux_device *dev); -static __inline struct ahd_linux_device * - ahd_linux_next_device_to_run(struct ahd_softc *ahd); -static __inline void ahd_linux_run_device_queues(struct ahd_softc *ahd); static __inline void ahd_linux_unmap_scb(struct ahd_softc*, struct scb*); static __inline void @@ -553,28 +534,6 @@ ahd_schedule_completeq(struct ahd_softc *ahd) } } -/* - * Must be called with our lock held. - */ -static __inline void -ahd_schedule_runq(struct ahd_softc *ahd) -{ - tasklet_schedule(&ahd->platform_data->runq_tasklet); -} - -static __inline -void ahd_setup_runq_tasklet(struct ahd_softc *ahd) -{ - tasklet_init(&ahd->platform_data->runq_tasklet, ahd_runq_tasklet, - (unsigned long)ahd); -} - -static __inline void -ahd_teardown_runq_tasklet(struct ahd_softc *ahd) -{ - tasklet_kill(&ahd->platform_data->runq_tasklet); -} - static __inline struct ahd_linux_device* ahd_linux_get_device(struct ahd_softc *ahd, u_int channel, u_int target, u_int lun, int alloc) @@ -640,46 +599,6 @@ ahd_linux_run_complete_queue(struct ahd_softc *ahd) return (acmd); } -static __inline void -ahd_linux_check_device_queue(struct ahd_softc *ahd, - struct ahd_linux_device *dev) -{ - if ((dev->flags & AHD_DEV_FREEZE_TIL_EMPTY) != 0 - && dev->active == 0) { - dev->flags &= ~AHD_DEV_FREEZE_TIL_EMPTY; - dev->qfrozen--; - } - - if (TAILQ_FIRST(&dev->busyq) == NULL - || dev->openings == 0 || dev->qfrozen != 0) - return; - - ahd_linux_run_device_queue(ahd, dev); -} - -static __inline struct ahd_linux_device * -ahd_linux_next_device_to_run(struct ahd_softc *ahd) -{ - - if ((ahd->flags & AHD_RESOURCE_SHORTAGE) != 0 - || (ahd->platform_data->qfrozen != 0 - && AHD_DV_SIMQ_FROZEN(ahd) == 0)) - return (NULL); - return (TAILQ_FIRST(&ahd->platform_data->device_runq)); -} - -static __inline void -ahd_linux_run_device_queues(struct ahd_softc *ahd) -{ - struct ahd_linux_device *dev; - - while ((dev = ahd_linux_next_device_to_run(ahd)) != NULL) { - TAILQ_REMOVE(&ahd->platform_data->device_runq, dev, links); - dev->flags &= ~AHD_DEV_ON_RUN_LIST; - ahd_linux_check_device_queue(ahd, dev); - } -} - static __inline void ahd_linux_unmap_scb(struct ahd_softc *ahd, struct scb *scb) { @@ -709,7 +628,6 @@ ahd_linux_unmap_scb(struct ahd_softc *ahd, struct scb *scb) static int ahd_linux_detect(Scsi_Host_Template *); static const char *ahd_linux_info(struct Scsi_Host *); static int ahd_linux_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *)); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) static int ahd_linux_slave_alloc(Scsi_Device *); static int ahd_linux_slave_configure(Scsi_Device *); static void ahd_linux_slave_destroy(Scsi_Device *); @@ -717,78 +635,10 @@ static void ahd_linux_slave_destroy(Scsi_Device *); static int ahd_linux_biosparam(struct scsi_device*, struct block_device*, sector_t, int[]); #endif -#else -static int ahd_linux_release(struct Scsi_Host *); -static void ahd_linux_select_queue_depth(struct Scsi_Host *host, - Scsi_Device *scsi_devs); -#if defined(__i386__) -static int ahd_linux_biosparam(Disk *, kdev_t, int[]); -#endif -#endif static int ahd_linux_bus_reset(Scsi_Cmnd *); static int ahd_linux_dev_reset(Scsi_Cmnd *); static int ahd_linux_abort(Scsi_Cmnd *); -/* - * Calculate a safe value for AHD_NSEG (as expressed through ahd_linux_nseg). - * - * In pre-2.5.X... - * The midlayer allocates an S/G array dynamically when a command is issued - * using SCSI malloc. This array, which is in an OS dependent format that - * must later be copied to our private S/G list, is sized to house just the - * number of segments needed for the current transfer. Since the code that - * sizes the SCSI malloc pool does not take into consideration fragmentation - * of the pool, executing transactions numbering just a fraction of our - * concurrent transaction limit with SG list lengths aproaching AHC_NSEG will - * quickly depleat the SCSI malloc pool of usable space. Unfortunately, the - * mid-layer does not properly handle this scsi malloc failures for the S/G - * array and the result can be a lockup of the I/O subsystem. We try to size - * our S/G list so that it satisfies our drivers allocation requirements in - * addition to avoiding fragmentation of the SCSI malloc pool. - */ -static void -ahd_linux_size_nseg(void) -{ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - u_int cur_size; - u_int best_size; - - /* - * The SCSI allocator rounds to the nearest 512 bytes - * an cannot allocate across a page boundary. Our algorithm - * is to start at 1K of scsi malloc space per-command and - * loop through all factors of the PAGE_SIZE and pick the best. - */ - best_size = 0; - for (cur_size = 1024; cur_size <= PAGE_SIZE; cur_size *= 2) { - u_int nseg; - - nseg = cur_size / sizeof(struct scatterlist); - if (nseg < AHD_LINUX_MIN_NSEG) - continue; - - if (best_size == 0) { - best_size = cur_size; - ahd_linux_nseg = nseg; - } else { - u_int best_rem; - u_int cur_rem; - - /* - * Compare the traits of the current "best_size" - * with the current size to determine if the - * current size is a better size. - */ - best_rem = best_size % sizeof(struct scatterlist); - cur_rem = cur_size % sizeof(struct scatterlist); - if (cur_rem < best_rem) { - best_size = cur_size; - ahd_linux_nseg = nseg; - } - } - } -#endif -} /* * Try to detect an Adaptec 79XX controller. @@ -800,14 +650,6 @@ ahd_linux_detect(Scsi_Host_Template *template) int found; int error = 0; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - /* - * It is a bug that the upper layer takes - * this lock just prior to calling us. - */ - spin_unlock_irq(&io_request_lock); -#endif - /* * Sanity checking of Linux SCSI data structures so * that some of our hacks^H^H^H^H^Hassumptions aren't @@ -819,10 +661,7 @@ ahd_linux_detect(Scsi_Host_Template *template) printf("ahd_linux_detect: Unable to attach\n"); return (0); } - /* - * Determine an appropriate size for our Scatter Gatther lists. - */ - ahd_linux_size_nseg(); + #ifdef MODULE /* * If we've been passed any parameters, process them now. @@ -855,47 +694,10 @@ ahd_linux_detect(Scsi_Host_Template *template) if (ahd_linux_register_host(ahd, template) == 0) found++; } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - spin_lock_irq(&io_request_lock); -#endif aic79xx_detect_complete++; return 0; } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) -/* - * Free the passed in Scsi_Host memory structures prior to unloading the - * module. - */ -static int -ahd_linux_release(struct Scsi_Host * host) -{ - struct ahd_softc *ahd; - u_long l; - - ahd_list_lock(&l); - if (host != NULL) { - - /* - * We should be able to just perform - * the free directly, but check our - * list for extra sanity. - */ - ahd = ahd_find_softc(*(struct ahd_softc **)host->hostdata); - if (ahd != NULL) { - u_long s; - - ahd_lock(ahd, &s); - ahd_intr_enable(ahd, FALSE); - ahd_unlock(ahd, &s); - ahd_free(ahd); - } - } - ahd_list_unlock(&l); - return (0); -} -#endif - /* * Return a string describing the driver. */ @@ -932,17 +734,9 @@ ahd_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *)) { struct ahd_softc *ahd; struct ahd_linux_device *dev; - u_long flags; ahd = *(struct ahd_softc **)cmd->device->host->hostdata; - /* - * Save the callback on completion function. - */ - cmd->scsi_done = scsi_done; - - ahd_midlayer_entrypoint_lock(ahd, &flags); - /* * Close the race of a command that was in the process of * being queued to us just as our simq was frozen. Let @@ -951,39 +745,26 @@ ahd_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *)) */ if (ahd->platform_data->qfrozen != 0 && AHD_DV_CMD(cmd) == 0) { + printf("%s: queue frozen\n", ahd_name(ahd)); - ahd_cmd_set_transaction_status(cmd, CAM_REQUEUE_REQ); - ahd_linux_queue_cmd_complete(ahd, cmd); - ahd_schedule_completeq(ahd); - ahd_midlayer_entrypoint_unlock(ahd, &flags); - return (0); + return SCSI_MLQUEUE_HOST_BUSY; } + + /* + * Save the callback on completion function. + */ + cmd->scsi_done = scsi_done; + dev = ahd_linux_get_device(ahd, cmd->device->channel, cmd->device->id, cmd->device->lun, /*alloc*/TRUE); - if (dev == NULL) { - ahd_cmd_set_transaction_status(cmd, CAM_RESRC_UNAVAIL); - ahd_linux_queue_cmd_complete(ahd, cmd); - ahd_schedule_completeq(ahd); - ahd_midlayer_entrypoint_unlock(ahd, &flags); - printf("%s: aic79xx_linux_queue - Unable to allocate device!\n", - ahd_name(ahd)); - return (0); - } - if (cmd->cmd_len > MAX_CDB_LEN) - return (-EINVAL); + BUG_ON(dev == NULL); + cmd->result = CAM_REQ_INPROG << 16; - TAILQ_INSERT_TAIL(&dev->busyq, (struct ahd_cmd *)cmd, acmd_links.tqe); - if ((dev->flags & AHD_DEV_ON_RUN_LIST) == 0) { - TAILQ_INSERT_TAIL(&ahd->platform_data->device_runq, dev, links); - dev->flags |= AHD_DEV_ON_RUN_LIST; - ahd_linux_run_device_queues(ahd); - } - ahd_midlayer_entrypoint_unlock(ahd, &flags); - return (0); + + return ahd_linux_run_command(ahd, dev, cmd); } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) static int ahd_linux_slave_alloc(Scsi_Device *device) { @@ -1049,99 +830,22 @@ ahd_linux_slave_destroy(Scsi_Device *device) if (dev != NULL && (dev->flags & AHD_DEV_SLAVE_CONFIGURED) != 0) { dev->flags |= AHD_DEV_UNCONFIGURED; - if (TAILQ_EMPTY(&dev->busyq) - && dev->active == 0 + if (dev->active == 0 && (dev->flags & AHD_DEV_TIMER_ACTIVE) == 0) ahd_linux_free_device(ahd, dev); } ahd_midlayer_entrypoint_unlock(ahd, &flags); } -#else -/* - * Sets the queue depth for each SCSI device hanging - * off the input host adapter. - */ -static void -ahd_linux_select_queue_depth(struct Scsi_Host * host, - Scsi_Device * scsi_devs) -{ - Scsi_Device *device; - Scsi_Device *ldev; - struct ahd_softc *ahd; - u_long flags; - - ahd = *((struct ahd_softc **)host->hostdata); - ahd_lock(ahd, &flags); - for (device = scsi_devs; device != NULL; device = device->next) { - - /* - * Watch out for duplicate devices. This works around - * some quirks in how the SCSI scanning code does its - * device management. - */ - for (ldev = scsi_devs; ldev != device; ldev = ldev->next) { - if (ldev->host == device->host - && ldev->channel == device->channel - && ldev->id == device->id - && ldev->lun == device->lun) - break; - } - /* Skip duplicate. */ - if (ldev != device) - continue; - - if (device->host == host) { - struct ahd_linux_device *dev; - - /* - * Since Linux has attached to the device, configure - * it so we don't free and allocate the device - * structure on every command. - */ - dev = ahd_linux_get_device(ahd, device->channel, - device->id, device->lun, - /*alloc*/TRUE); - if (dev != NULL) { - dev->flags &= ~AHD_DEV_UNCONFIGURED; - dev->scsi_device = device; - ahd_linux_device_queue_depth(ahd, dev); - device->queue_depth = dev->openings - + dev->active; - if ((dev->flags & (AHD_DEV_Q_BASIC - | AHD_DEV_Q_TAGGED)) == 0) { - /* - * We allow the OS to queue 2 untagged - * transactions to us at any time even - * though we can only execute them - * serially on the controller/device. - * This should remove some latency. - */ - device->queue_depth = 2; - } - } - } - } - ahd_unlock(ahd, &flags); -} -#endif #if defined(__i386__) /* * Return the disk geometry for the given SCSI device. */ static int -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ahd_linux_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[]) { uint8_t *bh; -#else -ahd_linux_biosparam(Disk *disk, kdev_t dev, int geom[]) -{ - struct scsi_device *sdev = disk->device; - u_long capacity = disk->capacity; - struct buffer_head *bh; -#endif int heads; int sectors; int cylinders; @@ -1151,22 +855,11 @@ ahd_linux_biosparam(Disk *disk, kdev_t dev, int geom[]) ahd = *((struct ahd_softc **)sdev->host->hostdata); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) bh = scsi_bios_ptable(bdev); -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,17) - bh = bread(MKDEV(MAJOR(dev), MINOR(dev) & ~0xf), 0, block_size(dev)); -#else - bh = bread(MKDEV(MAJOR(dev), MINOR(dev) & ~0xf), 0, 1024); -#endif - if (bh) { ret = scsi_partsize(bh, capacity, &geom[2], &geom[0], &geom[1]); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) kfree(bh); -#else - brelse(bh); -#endif if (ret != -1) return (ret); } @@ -1198,7 +891,6 @@ ahd_linux_abort(Scsi_Cmnd *cmd) { struct ahd_softc *ahd; struct ahd_cmd *acmd; - struct ahd_cmd *list_acmd; struct ahd_linux_device *dev; struct scb *pending_scb; u_long s; @@ -1265,22 +957,6 @@ ahd_linux_abort(Scsi_Cmnd *cmd) goto no_cmd; } - TAILQ_FOREACH(list_acmd, &dev->busyq, acmd_links.tqe) { - if (list_acmd == acmd) - break; - } - - if (list_acmd != NULL) { - printf("%s:%d:%d:%d: Command found on device queue\n", - ahd_name(ahd), cmd->device->channel, cmd->device->id, - cmd->device->lun); - TAILQ_REMOVE(&dev->busyq, list_acmd, acmd_links.tqe); - cmd->result = DID_ABORT << 16; - ahd_linux_queue_cmd_complete(ahd, cmd); - retval = SUCCESS; - goto done; - } - /* * See if we can find a matching cmd in the pending list. */ @@ -1468,7 +1144,6 @@ ahd_linux_abort(Scsi_Cmnd *cmd) } spin_lock_irq(&ahd->platform_data->spin_lock); } - ahd_schedule_runq(ahd); ahd_linux_run_complete_queue(ahd); ahd_midlayer_entrypoint_unlock(ahd, &s); return (retval); @@ -1568,7 +1243,6 @@ ahd_linux_dev_reset(Scsi_Cmnd *cmd) retval = FAILED; } ahd_lock(ahd, &s); - ahd_schedule_runq(ahd); ahd_linux_run_complete_queue(ahd); ahd_unlock(ahd, &s); printf("%s: Device reset returning 0x%x\n", ahd_name(ahd), retval); @@ -1625,35 +1299,6 @@ Scsi_Host_Template aic79xx_driver_template = { .slave_destroy = ahd_linux_slave_destroy, }; -/**************************** Tasklet Handler *********************************/ - -/* - * In 2.4.X and above, this routine is called from a tasklet, - * so we must re-acquire our lock prior to executing this code. - * In all prior kernels, ahd_schedule_runq() calls this routine - * directly and ahd_schedule_runq() is called with our lock held. - */ -static void -ahd_runq_tasklet(unsigned long data) -{ - struct ahd_softc* ahd; - struct ahd_linux_device *dev; - u_long flags; - - ahd = (struct ahd_softc *)data; - ahd_lock(ahd, &flags); - while ((dev = ahd_linux_next_device_to_run(ahd)) != NULL) { - - TAILQ_REMOVE(&ahd->platform_data->device_runq, dev, links); - dev->flags &= ~AHD_DEV_ON_RUN_LIST; - ahd_linux_check_device_queue(ahd, dev); - /* Yeild to our interrupt handler */ - ahd_unlock(ahd, &flags); - ahd_lock(ahd, &flags); - } - ahd_unlock(ahd, &flags); -} - /******************************** Bus DMA *************************************/ int ahd_dma_tag_create(struct ahd_softc *ahd, bus_dma_tag_t parent, @@ -1997,11 +1642,7 @@ ahd_linux_register_host(struct ahd_softc *ahd, Scsi_Host_Template *template) *((struct ahd_softc **)host->hostdata) = ahd; ahd_lock(ahd, &s); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) scsi_assign_lock(host, &ahd->platform_data->spin_lock); -#elif AHD_SCSI_HAS_HOST_LOCK != 0 - host->lock = &ahd->platform_data->spin_lock; -#endif ahd->platform_data->host = host; host->can_queue = AHD_MAX_QUEUE; host->cmd_per_lun = 2; @@ -2020,9 +1661,6 @@ ahd_linux_register_host(struct ahd_softc *ahd, Scsi_Host_Template *template) ahd_set_name(ahd, new_name); } host->unique_id = ahd->unit; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - scsi_set_pci_device(host, ahd->dev_softc); -#endif ahd_linux_setup_user_rd_strm_settings(ahd); ahd_linux_initialize_scsi_bus(ahd); ahd_unlock(ahd, &s); @@ -2064,10 +1702,8 @@ ahd_linux_register_host(struct ahd_softc *ahd, Scsi_Host_Template *template) ahd_linux_start_dv(ahd); ahd_unlock(ahd, &s); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) scsi_add_host(host, &ahd->dev_softc->dev); /* XXX handle failure */ scsi_scan_host(host); -#endif return (0); } @@ -2163,7 +1799,6 @@ ahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg) return (ENOMEM); memset(ahd->platform_data, 0, sizeof(struct ahd_platform_data)); TAILQ_INIT(&ahd->platform_data->completeq); - TAILQ_INIT(&ahd->platform_data->device_runq); ahd->platform_data->irq = AHD_LINUX_NOIRQ; ahd->platform_data->hw_dma_mask = 0xFFFFFFFF; ahd_lockinit(ahd); @@ -2175,7 +1810,6 @@ ahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg) init_MUTEX_LOCKED(&ahd->platform_data->eh_sem); init_MUTEX_LOCKED(&ahd->platform_data->dv_sem); init_MUTEX_LOCKED(&ahd->platform_data->dv_cmd_sem); - ahd_setup_runq_tasklet(ahd); ahd->seltime = (aic79xx_seltime & 0x3) << 4; return (0); } @@ -2190,11 +1824,8 @@ ahd_platform_free(struct ahd_softc *ahd) if (ahd->platform_data != NULL) { del_timer_sync(&ahd->platform_data->completeq_timer); ahd_linux_kill_dv_thread(ahd); - ahd_teardown_runq_tasklet(ahd); if (ahd->platform_data->host != NULL) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) scsi_remove_host(ahd->platform_data->host); -#endif scsi_host_put(ahd->platform_data->host); } @@ -2233,16 +1864,6 @@ ahd_platform_free(struct ahd_softc *ahd) release_mem_region(ahd->platform_data->mem_busaddr, 0x1000); } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - /* - * In 2.4 we detach from the scsi midlayer before the PCI - * layer invokes our remove callback. No per-instance - * detach is provided, so we must reach inside the PCI - * subsystem's internals and detach our driver manually. - */ - if (ahd->dev_softc != NULL) - ahd->dev_softc->driver = NULL; -#endif free(ahd->platform_data, M_DEVBUF); } } @@ -2339,7 +1960,7 @@ ahd_platform_set_tags(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, dev->maxtags = 0; dev->openings = 1 - dev->active; } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) + if (dev->scsi_device != NULL) { switch ((dev->flags & (AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED))) { case AHD_DEV_Q_BASIC: @@ -2365,65 +1986,13 @@ ahd_platform_set_tags(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, break; } } -#endif } int ahd_platform_abort_scbs(struct ahd_softc *ahd, int target, char channel, int lun, u_int tag, role_t role, uint32_t status) { - int targ; - int maxtarg; - int maxlun; - int clun; - int count; - - if (tag != SCB_LIST_NULL) - return (0); - - targ = 0; - if (target != CAM_TARGET_WILDCARD) { - targ = target; - maxtarg = targ + 1; - } else { - maxtarg = (ahd->features & AHD_WIDE) ? 16 : 8; - } - clun = 0; - if (lun != CAM_LUN_WILDCARD) { - clun = lun; - maxlun = clun + 1; - } else { - maxlun = AHD_NUM_LUNS; - } - - count = 0; - for (; targ < maxtarg; targ++) { - - for (; clun < maxlun; clun++) { - struct ahd_linux_device *dev; - struct ahd_busyq *busyq; - struct ahd_cmd *acmd; - - dev = ahd_linux_get_device(ahd, /*chan*/0, targ, - clun, /*alloc*/FALSE); - if (dev == NULL) - continue; - - busyq = &dev->busyq; - while ((acmd = TAILQ_FIRST(busyq)) != NULL) { - Scsi_Cmnd *cmd; - - cmd = &acmd_scsi_cmd(acmd); - TAILQ_REMOVE(busyq, acmd, - acmd_links.tqe); - count++; - cmd->result = status << 16; - ahd_linux_queue_cmd_complete(ahd, cmd); - } - } - } - - return (count); + return 0; } static void @@ -2478,18 +2047,10 @@ ahd_linux_dv_thread(void *data) * Complete thread creation. */ lock_kernel(); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,60) - /* - * Don't care about any signals. - */ - siginitsetinv(¤t->blocked, 0); - daemonize(); - sprintf(current->comm, "ahd_dv_%d", ahd->unit); -#else daemonize("ahd_dv_%d", ahd->unit); - current->flags |= PF_NOFREEZE; -#endif + current->flags |= PF_FREEZE; + unlock_kernel(); while (1) { @@ -3685,8 +3246,6 @@ ahd_linux_dv_timeout(struct scsi_cmnd *cmd) ahd->platform_data->reset_timer.function = (ahd_linux_callback_t *)ahd_release_simq; add_timer(&ahd->platform_data->reset_timer); - if (ahd_linux_next_device_to_run(ahd) != NULL) - ahd_schedule_runq(ahd); ahd_linux_run_complete_queue(ahd); ahd_unlock(ahd, &flags); } @@ -3903,11 +3462,10 @@ ahd_linux_device_queue_depth(struct ahd_softc *ahd, } } -static void -ahd_linux_run_device_queue(struct ahd_softc *ahd, struct ahd_linux_device *dev) +static int +ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev, + struct scsi_cmnd *cmd) { - struct ahd_cmd *acmd; - struct scsi_cmnd *cmd; struct scb *scb; struct hardware_scb *hscb; struct ahd_initiator_tinfo *tinfo; @@ -3915,157 +3473,132 @@ ahd_linux_run_device_queue(struct ahd_softc *ahd, struct ahd_linux_device *dev) u_int col_idx; uint16_t mask; - if ((dev->flags & AHD_DEV_ON_RUN_LIST) != 0) - panic("running device on run list"); - - while ((acmd = TAILQ_FIRST(&dev->busyq)) != NULL - && dev->openings > 0 && dev->qfrozen == 0) { - - /* - * Schedule us to run later. The only reason we are not - * running is because the whole controller Q is frozen. - */ - if (ahd->platform_data->qfrozen != 0 - && AHD_DV_SIMQ_FROZEN(ahd) == 0) { - - TAILQ_INSERT_TAIL(&ahd->platform_data->device_runq, - dev, links); - dev->flags |= AHD_DEV_ON_RUN_LIST; - return; - } - - cmd = &acmd_scsi_cmd(acmd); - - /* - * Get an scb to use. - */ - tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id, - cmd->device->id, &tstate); - if ((dev->flags & (AHD_DEV_Q_TAGGED|AHD_DEV_Q_BASIC)) == 0 - || (tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0) { - col_idx = AHD_NEVER_COL_IDX; - } else { - col_idx = AHD_BUILD_COL_IDX(cmd->device->id, - cmd->device->lun); - } - if ((scb = ahd_get_scb(ahd, col_idx)) == NULL) { - TAILQ_INSERT_TAIL(&ahd->platform_data->device_runq, - dev, links); - dev->flags |= AHD_DEV_ON_RUN_LIST; - ahd->flags |= AHD_RESOURCE_SHORTAGE; - return; - } - TAILQ_REMOVE(&dev->busyq, acmd, acmd_links.tqe); - scb->io_ctx = cmd; - scb->platform_data->dev = dev; - hscb = scb->hscb; - cmd->host_scribble = (char *)scb; - - /* - * Fill out basics of the HSCB. - */ - hscb->control = 0; - hscb->scsiid = BUILD_SCSIID(ahd, cmd); - hscb->lun = cmd->device->lun; - scb->hscb->task_management = 0; - mask = SCB_GET_TARGET_MASK(ahd, scb); - - if ((ahd->user_discenable & mask) != 0) - hscb->control |= DISCENB; - - if (AHD_DV_CMD(cmd) != 0) - scb->flags |= SCB_SILENT; - - if ((tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0) - scb->flags |= SCB_PACKETIZED; - - if ((tstate->auto_negotiate & mask) != 0) { - scb->flags |= SCB_AUTO_NEGOTIATE; - scb->hscb->control |= MK_MESSAGE; - } - - if ((dev->flags & (AHD_DEV_Q_TAGGED|AHD_DEV_Q_BASIC)) != 0) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) - int msg_bytes; - uint8_t tag_msgs[2]; - - msg_bytes = scsi_populate_tag_msg(cmd, tag_msgs); - if (msg_bytes && tag_msgs[0] != MSG_SIMPLE_TASK) { - hscb->control |= tag_msgs[0]; - if (tag_msgs[0] == MSG_ORDERED_TASK) - dev->commands_since_idle_or_otag = 0; - } else -#endif - if (dev->commands_since_idle_or_otag == AHD_OTAG_THRESH - && (dev->flags & AHD_DEV_Q_TAGGED) != 0) { - hscb->control |= MSG_ORDERED_TASK; - dev->commands_since_idle_or_otag = 0; - } else { - hscb->control |= MSG_SIMPLE_TASK; - } - } - - hscb->cdb_len = cmd->cmd_len; - memcpy(hscb->shared_data.idata.cdb, cmd->cmnd, hscb->cdb_len); - - scb->sg_count = 0; - ahd_set_residual(scb, 0); - ahd_set_sense_residual(scb, 0); - if (cmd->use_sg != 0) { - void *sg; - struct scatterlist *cur_seg; - u_int nseg; - int dir; - - cur_seg = (struct scatterlist *)cmd->request_buffer; - dir = cmd->sc_data_direction; - nseg = pci_map_sg(ahd->dev_softc, cur_seg, - cmd->use_sg, dir); - scb->platform_data->xfer_len = 0; - for (sg = scb->sg_list; nseg > 0; nseg--, cur_seg++) { - dma_addr_t addr; - bus_size_t len; - - addr = sg_dma_address(cur_seg); - len = sg_dma_len(cur_seg); - scb->platform_data->xfer_len += len; - sg = ahd_sg_setup(ahd, scb, sg, addr, len, - /*last*/nseg == 1); - } - } else if (cmd->request_bufflen != 0) { - void *sg; - dma_addr_t addr; - int dir; - - sg = scb->sg_list; - dir = cmd->sc_data_direction; - addr = pci_map_single(ahd->dev_softc, - cmd->request_buffer, - cmd->request_bufflen, dir); - scb->platform_data->xfer_len = cmd->request_bufflen; - scb->platform_data->buf_busaddr = addr; - sg = ahd_sg_setup(ahd, scb, sg, addr, - cmd->request_bufflen, /*last*/TRUE); - } - - LIST_INSERT_HEAD(&ahd->pending_scbs, scb, pending_links); - dev->openings--; - dev->active++; - dev->commands_issued++; - - /* Update the error counting bucket and dump if needed */ - if (dev->target->cmds_since_error) { - dev->target->cmds_since_error++; - if (dev->target->cmds_since_error > - AHD_LINUX_ERR_THRESH) - dev->target->cmds_since_error = 0; - } - - if ((dev->flags & AHD_DEV_PERIODIC_OTAG) != 0) - dev->commands_since_idle_or_otag++; - scb->flags |= SCB_ACTIVE; - ahd_queue_scb(ahd, scb); + /* + * Get an scb to use. + */ + tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id, + cmd->device->id, &tstate); + if ((dev->flags & (AHD_DEV_Q_TAGGED|AHD_DEV_Q_BASIC)) == 0 + || (tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0) { + col_idx = AHD_NEVER_COL_IDX; + } else { + col_idx = AHD_BUILD_COL_IDX(cmd->device->id, + cmd->device->lun); } + if ((scb = ahd_get_scb(ahd, col_idx)) == NULL) { + ahd->flags |= AHD_RESOURCE_SHORTAGE; + return SCSI_MLQUEUE_HOST_BUSY; + } + + scb->io_ctx = cmd; + scb->platform_data->dev = dev; + hscb = scb->hscb; + cmd->host_scribble = (char *)scb; + + /* + * Fill out basics of the HSCB. + */ + hscb->control = 0; + hscb->scsiid = BUILD_SCSIID(ahd, cmd); + hscb->lun = cmd->device->lun; + scb->hscb->task_management = 0; + mask = SCB_GET_TARGET_MASK(ahd, scb); + + if ((ahd->user_discenable & mask) != 0) + hscb->control |= DISCENB; + + if (AHD_DV_CMD(cmd) != 0) + scb->flags |= SCB_SILENT; + + if ((tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0) + scb->flags |= SCB_PACKETIZED; + + if ((tstate->auto_negotiate & mask) != 0) { + scb->flags |= SCB_AUTO_NEGOTIATE; + scb->hscb->control |= MK_MESSAGE; + } + + if ((dev->flags & (AHD_DEV_Q_TAGGED|AHD_DEV_Q_BASIC)) != 0) { + int msg_bytes; + uint8_t tag_msgs[2]; + + msg_bytes = scsi_populate_tag_msg(cmd, tag_msgs); + if (msg_bytes && tag_msgs[0] != MSG_SIMPLE_TASK) { + hscb->control |= tag_msgs[0]; + if (tag_msgs[0] == MSG_ORDERED_TASK) + dev->commands_since_idle_or_otag = 0; + } else + if (dev->commands_since_idle_or_otag == AHD_OTAG_THRESH + && (dev->flags & AHD_DEV_Q_TAGGED) != 0) { + hscb->control |= MSG_ORDERED_TASK; + dev->commands_since_idle_or_otag = 0; + } else { + hscb->control |= MSG_SIMPLE_TASK; + } + } + + hscb->cdb_len = cmd->cmd_len; + memcpy(hscb->shared_data.idata.cdb, cmd->cmnd, hscb->cdb_len); + + scb->sg_count = 0; + ahd_set_residual(scb, 0); + ahd_set_sense_residual(scb, 0); + if (cmd->use_sg != 0) { + void *sg; + struct scatterlist *cur_seg; + u_int nseg; + int dir; + + cur_seg = (struct scatterlist *)cmd->request_buffer; + dir = cmd->sc_data_direction; + nseg = pci_map_sg(ahd->dev_softc, cur_seg, + cmd->use_sg, dir); + scb->platform_data->xfer_len = 0; + for (sg = scb->sg_list; nseg > 0; nseg--, cur_seg++) { + dma_addr_t addr; + bus_size_t len; + + addr = sg_dma_address(cur_seg); + len = sg_dma_len(cur_seg); + scb->platform_data->xfer_len += len; + sg = ahd_sg_setup(ahd, scb, sg, addr, len, + /*last*/nseg == 1); + } + } else if (cmd->request_bufflen != 0) { + void *sg; + dma_addr_t addr; + int dir; + + sg = scb->sg_list; + dir = cmd->sc_data_direction; + addr = pci_map_single(ahd->dev_softc, + cmd->request_buffer, + cmd->request_bufflen, dir); + scb->platform_data->xfer_len = cmd->request_bufflen; + scb->platform_data->buf_busaddr = addr; + sg = ahd_sg_setup(ahd, scb, sg, addr, + cmd->request_bufflen, /*last*/TRUE); + } + + LIST_INSERT_HEAD(&ahd->pending_scbs, scb, pending_links); + dev->openings--; + dev->active++; + dev->commands_issued++; + + /* Update the error counting bucket and dump if needed */ + if (dev->target->cmds_since_error) { + dev->target->cmds_since_error++; + if (dev->target->cmds_since_error > + AHD_LINUX_ERR_THRESH) + dev->target->cmds_since_error = 0; + } + + if ((dev->flags & AHD_DEV_PERIODIC_OTAG) != 0) + dev->commands_since_idle_or_otag++; + scb->flags |= SCB_ACTIVE; + ahd_queue_scb(ahd, scb); + + return 0; } /* @@ -4081,8 +3614,6 @@ ahd_linux_isr(int irq, void *dev_id, struct pt_regs * regs) ahd = (struct ahd_softc *) dev_id; ahd_lock(ahd, &flags); ours = ahd_intr(ahd); - if (ahd_linux_next_device_to_run(ahd) != NULL) - ahd_schedule_runq(ahd); ahd_linux_run_complete_queue(ahd); ahd_unlock(ahd, &flags); return IRQ_RETVAL(ours); @@ -4161,7 +3692,6 @@ ahd_linux_alloc_device(struct ahd_softc *ahd, return (NULL); memset(dev, 0, sizeof(*dev)); init_timer(&dev->timer); - TAILQ_INIT(&dev->busyq); dev->flags = AHD_DEV_UNCONFIGURED; dev->lun = lun; dev->target = targ; @@ -4264,28 +3794,9 @@ ahd_send_async(struct ahd_softc *ahd, char channel, } case AC_SENT_BDR: { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) WARN_ON(lun != CAM_LUN_WILDCARD); scsi_report_device_reset(ahd->platform_data->host, channel - 'A', target); -#else - Scsi_Device *scsi_dev; - - /* - * Find the SCSI device associated with this - * request and indicate that a UA is expected. - */ - for (scsi_dev = ahd->platform_data->host->host_queue; - scsi_dev != NULL; scsi_dev = scsi_dev->next) { - if (channel - 'A' == scsi_dev->channel - && target == scsi_dev->id - && (lun == CAM_LUN_WILDCARD - || lun == scsi_dev->lun)) { - scsi_dev->was_reset = 1; - scsi_dev->expecting_cc_ua = 1; - } - } -#endif break; } case AC_BUS_RESET: @@ -4406,15 +3917,10 @@ ahd_done(struct ahd_softc *ahd, struct scb *scb) if (dev->active == 0) dev->commands_since_idle_or_otag = 0; - if (TAILQ_EMPTY(&dev->busyq)) { - if ((dev->flags & AHD_DEV_UNCONFIGURED) != 0 - && dev->active == 0 - && (dev->flags & AHD_DEV_TIMER_ACTIVE) == 0) - ahd_linux_free_device(ahd, dev); - } else if ((dev->flags & AHD_DEV_ON_RUN_LIST) == 0) { - TAILQ_INSERT_TAIL(&ahd->platform_data->device_runq, dev, links); - dev->flags |= AHD_DEV_ON_RUN_LIST; - } + if ((dev->flags & AHD_DEV_UNCONFIGURED) != 0 + && dev->active == 0 + && (dev->flags & AHD_DEV_TIMER_ACTIVE) == 0) + ahd_linux_free_device(ahd, dev); if ((scb->flags & SCB_RECOVERY_SCB) != 0) { printf("Recovery SCB completes\n"); @@ -4887,7 +4393,6 @@ ahd_release_simq(struct ahd_softc *ahd) ahd->platform_data->flags &= ~AHD_DV_WAIT_SIMQ_RELEASE; up(&ahd->platform_data->dv_sem); } - ahd_schedule_runq(ahd); ahd_unlock(ahd, &s); /* * There is still a race here. The mid-layer @@ -4929,61 +4434,16 @@ ahd_linux_dev_timed_unfreeze(u_long arg) dev->flags &= ~AHD_DEV_TIMER_ACTIVE; if (dev->qfrozen > 0) dev->qfrozen--; - if (dev->qfrozen == 0 - && (dev->flags & AHD_DEV_ON_RUN_LIST) == 0) - ahd_linux_run_device_queue(ahd, dev); if ((dev->flags & AHD_DEV_UNCONFIGURED) != 0 && dev->active == 0) ahd_linux_free_device(ahd, dev); ahd_unlock(ahd, &s); } -void -ahd_platform_dump_card_state(struct ahd_softc *ahd) -{ - struct ahd_linux_device *dev; - int target; - int maxtarget; - int lun; - int i; - - maxtarget = (ahd->features & AHD_WIDE) ? 15 : 7; - for (target = 0; target <=maxtarget; target++) { - - for (lun = 0; lun < AHD_NUM_LUNS; lun++) { - struct ahd_cmd *acmd; - - dev = ahd_linux_get_device(ahd, 0, target, - lun, /*alloc*/FALSE); - if (dev == NULL) - continue; - - printf("DevQ(%d:%d:%d): ", 0, target, lun); - i = 0; - TAILQ_FOREACH(acmd, &dev->busyq, acmd_links.tqe) { - if (i++ > AHD_SCB_MAX) - break; - } - printf("%d waiting\n", i); - } - } -} - static int __init ahd_linux_init(void) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) return ahd_linux_detect(&aic79xx_driver_template); -#else - scsi_register_module(MODULE_SCSI_HA, &aic79xx_driver_template); - if (aic79xx_driver_template.present == 0) { - scsi_unregister_module(MODULE_SCSI_HA, - &aic79xx_driver_template); - return (-ENODEV); - } - - return (0); -#endif } static void __exit @@ -5002,14 +4462,6 @@ ahd_linux_exit(void) ahd_linux_kill_dv_thread(ahd); } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - /* - * In 2.4 we have to unregister from the PCI core _after_ - * unregistering from the scsi midlayer to avoid dangling - * references. - */ - scsi_unregister_module(MODULE_SCSI_HA, &aic79xx_driver_template); -#endif ahd_linux_pci_exit(); } diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h index 7823e52e99ab..792e97fef5b8 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.h +++ b/drivers/scsi/aic7xxx/aic79xx_osm.h @@ -252,11 +252,7 @@ ahd_scb_timer_reset(struct scb *scb, u_int usec) /***************************** SMP support ************************************/ #include -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) || defined(SCSI_HAS_HOST_LOCK)) #define AHD_SCSI_HAS_HOST_LOCK 1 -#else -#define AHD_SCSI_HAS_HOST_LOCK 0 -#endif #define AIC79XX_DRIVER_VERSION "1.3.11" @@ -297,12 +293,11 @@ struct ahd_cmd { * after a successfully completed inquiry command to the target when * that inquiry data indicates a lun is present. */ -TAILQ_HEAD(ahd_busyq, ahd_cmd); + typedef enum { AHD_DEV_UNCONFIGURED = 0x01, AHD_DEV_FREEZE_TIL_EMPTY = 0x02, /* Freeze queue until active == 0 */ AHD_DEV_TIMER_ACTIVE = 0x04, /* Our timer is active */ - AHD_DEV_ON_RUN_LIST = 0x08, /* Queued to be run later */ AHD_DEV_Q_BASIC = 0x10, /* Allow basic device queuing */ AHD_DEV_Q_TAGGED = 0x20, /* Allow full SCSI2 command queueing */ AHD_DEV_PERIODIC_OTAG = 0x40, /* Send OTAG to prevent starvation */ @@ -312,7 +307,6 @@ typedef enum { struct ahd_linux_target; struct ahd_linux_device { TAILQ_ENTRY(ahd_linux_device) links; - struct ahd_busyq busyq; /* * The number of transactions currently @@ -453,18 +447,7 @@ struct ahd_linux_target { * manner and are allocated below 4GB, the number of S/G segments is * unrestricted. */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) -/* - * We dynamically adjust the number of segments in pre-2.5 kernels to - * avoid fragmentation issues in the SCSI mid-layer's private memory - * allocator. See aic79xx_osm.c ahd_linux_size_nseg() for details. - */ -extern u_int ahd_linux_nseg; -#define AHD_NSEG ahd_linux_nseg -#define AHD_LINUX_MIN_NSEG 64 -#else #define AHD_NSEG 128 -#endif /* * Per-SCB OSM storage. @@ -502,11 +485,9 @@ struct ahd_platform_data { * Fields accessed from interrupt context. */ struct ahd_linux_target *targets[AHD_NUM_TARGETS]; - TAILQ_HEAD(, ahd_linux_device) device_runq; struct ahd_completeq completeq; spinlock_t spin_lock; - struct tasklet_struct runq_tasklet; u_int qfrozen; pid_t dv_pid; struct timer_list completeq_timer; @@ -925,12 +906,8 @@ ahd_flush_device_writes(struct ahd_softc *ahd) } /**************************** Proc FS Support *********************************/ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) -int ahd_linux_proc_info(char *, char **, off_t, int, int, int); -#else int ahd_linux_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int); -#endif /*************************** Domain Validation ********************************/ #define AHD_DV_CMD(cmd) ((cmd)->scsi_done == ahd_linux_dv_complete) @@ -1117,7 +1094,6 @@ void ahd_done(struct ahd_softc*, struct scb*); void ahd_send_async(struct ahd_softc *, char channel, u_int target, u_int lun, ac_code, void *); void ahd_print_path(struct ahd_softc *, struct scb *); -void ahd_platform_dump_card_state(struct ahd_softc *ahd); #ifdef CONFIG_PCI #define AHD_PCI_CONFIG 1 diff --git a/drivers/scsi/aic7xxx/aic79xx_proc.c b/drivers/scsi/aic7xxx/aic79xx_proc.c index e01cd6175e34..9c631a494ed2 100644 --- a/drivers/scsi/aic7xxx/aic79xx_proc.c +++ b/drivers/scsi/aic7xxx/aic79xx_proc.c @@ -278,13 +278,8 @@ ahd_proc_write_seeprom(struct ahd_softc *ahd, char *buffer, int length) * Return information to handle /proc support for the driver. */ int -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) -ahd_linux_proc_info(char *buffer, char **start, off_t offset, - int length, int hostno, int inout) -#else ahd_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start, off_t offset, int length, int inout) -#endif { struct ahd_softc *ahd; struct info_str info; @@ -296,14 +291,7 @@ ahd_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start, retval = -EINVAL; ahd_list_lock(&l); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) - TAILQ_FOREACH(ahd, &ahd_tailq, links) { - if (ahd->platform_data->host->host_no == hostno) - break; - } -#else ahd = ahd_find_softc(*(struct ahd_softc **)shost->hostdata); -#endif if (ahd == NULL) goto done; From 73a25462100772b72a5d62fd66dff01b53018618 Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Fri, 22 Jul 2005 16:44:04 +0200 Subject: [PATCH 025/114] [SCSI] aic79xx: update to use scsi_transport_spi This patch updates the aic79xx driver to take advantage of the scsi_transport_spi infrastructure. Patch is quite a mess as some procedures have been reshuffled to be closer to the aic7xxx driver. Rejections fixed and Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic79xx_osm.c | 3439 ++++++--------------------- drivers/scsi/aic7xxx/aic79xx_osm.h | 197 +- drivers/scsi/aic7xxx/aic79xx_proc.c | 18 +- 3 files changed, 808 insertions(+), 2846 deletions(-) diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index 7463dd515d11..70997ca28baa 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -46,6 +46,8 @@ #include "aic79xx_inline.h" #include +static struct scsi_transport_template *ahd_linux_transport_template = NULL; + /* * Include aiclib.c as part of our * "module dependencies are hard" work around. @@ -54,6 +56,7 @@ #include /* __setup */ #include /* For fetching system memory size */ +#include /* For block_size() */ #include /* For ssleep/msleep */ /* @@ -177,71 +180,6 @@ static adapter_tag_info_t aic79xx_tag_info[] = {AIC79XX_CONFIGED_TAG_COMMANDS} }; -/* - * By default, read streaming is disabled. In theory, - * read streaming should enhance performance, but early - * U320 drive firmware actually performs slower with - * read streaming enabled. - */ -#ifdef CONFIG_AIC79XX_ENABLE_RD_STRM -#define AIC79XX_CONFIGED_RD_STRM 0xFFFF -#else -#define AIC79XX_CONFIGED_RD_STRM 0 -#endif - -static uint16_t aic79xx_rd_strm_info[] = -{ - AIC79XX_CONFIGED_RD_STRM, - AIC79XX_CONFIGED_RD_STRM, - AIC79XX_CONFIGED_RD_STRM, - AIC79XX_CONFIGED_RD_STRM, - AIC79XX_CONFIGED_RD_STRM, - AIC79XX_CONFIGED_RD_STRM, - AIC79XX_CONFIGED_RD_STRM, - AIC79XX_CONFIGED_RD_STRM, - AIC79XX_CONFIGED_RD_STRM, - AIC79XX_CONFIGED_RD_STRM, - AIC79XX_CONFIGED_RD_STRM, - AIC79XX_CONFIGED_RD_STRM, - AIC79XX_CONFIGED_RD_STRM, - AIC79XX_CONFIGED_RD_STRM, - AIC79XX_CONFIGED_RD_STRM, - AIC79XX_CONFIGED_RD_STRM -}; - -/* - * DV option: - * - * positive value = DV Enabled - * zero = DV Disabled - * negative value = DV Default for adapter type/seeprom - */ -#ifdef CONFIG_AIC79XX_DV_SETTING -#define AIC79XX_CONFIGED_DV CONFIG_AIC79XX_DV_SETTING -#else -#define AIC79XX_CONFIGED_DV -1 -#endif - -static int8_t aic79xx_dv_settings[] = -{ - AIC79XX_CONFIGED_DV, - AIC79XX_CONFIGED_DV, - AIC79XX_CONFIGED_DV, - AIC79XX_CONFIGED_DV, - AIC79XX_CONFIGED_DV, - AIC79XX_CONFIGED_DV, - AIC79XX_CONFIGED_DV, - AIC79XX_CONFIGED_DV, - AIC79XX_CONFIGED_DV, - AIC79XX_CONFIGED_DV, - AIC79XX_CONFIGED_DV, - AIC79XX_CONFIGED_DV, - AIC79XX_CONFIGED_DV, - AIC79XX_CONFIGED_DV, - AIC79XX_CONFIGED_DV, - AIC79XX_CONFIGED_DV -}; - /* * The I/O cell on the chip is very configurable in respect to its analog * characteristics. Set the defaults here; they can be overriden with @@ -402,7 +340,7 @@ MODULE_AUTHOR("Maintainer: Justin T. Gibbs "); MODULE_DESCRIPTION("Adaptec Aic790X U320 SCSI Host Bus Adapter driver"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_VERSION(AIC79XX_DRIVER_VERSION); -module_param(aic79xx, charp, 0); +module_param(aic79xx, charp, 0444); MODULE_PARM_DESC(aic79xx, "period delimited, options string.\n" " verbose Enable verbose/diagnostic logging\n" @@ -417,8 +355,6 @@ MODULE_PARM_DESC(aic79xx, " reverse_scan Sort PCI devices highest Bus/Slot to lowest\n" " tag_info: Set per-target tag depth\n" " global_tag_depth: Global tag depth for all targets on all buses\n" -" rd_strm: Set per-target read streaming setting.\n" -" dv: Set per-controller Domain Validation Setting.\n" " slewrate:Set the signal slew rate (0-15).\n" " precomp: Set the signal precompensation (0-7).\n" " amplitude: Set the signal amplitude (0-7).\n" @@ -431,178 +367,35 @@ MODULE_PARM_DESC(aic79xx, " Shorten the selection timeout to 128ms\n" "\n" " options aic79xx 'aic79xx=verbose.tag_info:{{}.{}.{..10}}.seltime:1'\n" -"\n" -" Sample /etc/modprobe.conf line:\n" -" Change Read Streaming for Controller's 2 and 3\n" -"\n" -" options aic79xx 'aic79xx=rd_strm:{..0xFFF0.0xC0F0}'"); +"\n"); static void ahd_linux_handle_scsi_status(struct ahd_softc *, - struct ahd_linux_device *, + struct scsi_device *, struct scb *); static void ahd_linux_queue_cmd_complete(struct ahd_softc *ahd, - Scsi_Cmnd *cmd); -static void ahd_linux_filter_inquiry(struct ahd_softc *ahd, - struct ahd_devinfo *devinfo); -static void ahd_linux_dev_timed_unfreeze(u_long arg); + struct scsi_cmnd *cmd); static void ahd_linux_sem_timeout(u_long arg); +static int ahd_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag); static void ahd_linux_initialize_scsi_bus(struct ahd_softc *ahd); -static void ahd_linux_thread_run_complete_queue(struct ahd_softc *ahd); -static void ahd_linux_start_dv(struct ahd_softc *ahd); -static void ahd_linux_dv_timeout(struct scsi_cmnd *cmd); -static int ahd_linux_dv_thread(void *data); -static void ahd_linux_kill_dv_thread(struct ahd_softc *ahd); -static void ahd_linux_dv_target(struct ahd_softc *ahd, u_int target); -static void ahd_linux_dv_transition(struct ahd_softc *ahd, - struct scsi_cmnd *cmd, - struct ahd_devinfo *devinfo, - struct ahd_linux_target *targ); -static void ahd_linux_dv_fill_cmd(struct ahd_softc *ahd, - struct scsi_cmnd *cmd, - struct ahd_devinfo *devinfo); -static void ahd_linux_dv_inq(struct ahd_softc *ahd, - struct scsi_cmnd *cmd, - struct ahd_devinfo *devinfo, - struct ahd_linux_target *targ, - u_int request_length); -static void ahd_linux_dv_tur(struct ahd_softc *ahd, - struct scsi_cmnd *cmd, - struct ahd_devinfo *devinfo); -static void ahd_linux_dv_rebd(struct ahd_softc *ahd, - struct scsi_cmnd *cmd, - struct ahd_devinfo *devinfo, - struct ahd_linux_target *targ); -static void ahd_linux_dv_web(struct ahd_softc *ahd, - struct scsi_cmnd *cmd, - struct ahd_devinfo *devinfo, - struct ahd_linux_target *targ); -static void ahd_linux_dv_reb(struct ahd_softc *ahd, - struct scsi_cmnd *cmd, - struct ahd_devinfo *devinfo, - struct ahd_linux_target *targ); -static void ahd_linux_dv_su(struct ahd_softc *ahd, - struct scsi_cmnd *cmd, - struct ahd_devinfo *devinfo, - struct ahd_linux_target *targ); -static int ahd_linux_fallback(struct ahd_softc *ahd, - struct ahd_devinfo *devinfo); -static __inline int ahd_linux_dv_fallback(struct ahd_softc *ahd, - struct ahd_devinfo *devinfo); -static void ahd_linux_dv_complete(Scsi_Cmnd *cmd); -static void ahd_linux_generate_dv_pattern(struct ahd_linux_target *targ); static u_int ahd_linux_user_tagdepth(struct ahd_softc *ahd, struct ahd_devinfo *devinfo); -static u_int ahd_linux_user_dv_setting(struct ahd_softc *ahd); -static void ahd_linux_setup_user_rd_strm_settings(struct ahd_softc *ahd); -static void ahd_linux_device_queue_depth(struct ahd_softc *ahd, - struct ahd_linux_device *dev); -static struct ahd_linux_target* ahd_linux_alloc_target(struct ahd_softc*, - u_int, u_int); -static void ahd_linux_free_target(struct ahd_softc*, - struct ahd_linux_target*); -static struct ahd_linux_device* ahd_linux_alloc_device(struct ahd_softc*, - struct ahd_linux_target*, - u_int); -static void ahd_linux_free_device(struct ahd_softc*, - struct ahd_linux_device*); +static void ahd_linux_device_queue_depth(struct scsi_device *); static int ahd_linux_run_command(struct ahd_softc*, - struct ahd_linux_device*, + struct ahd_linux_device *, struct scsi_cmnd *); static void ahd_linux_setup_tag_info_global(char *p); static aic_option_callback_t ahd_linux_setup_tag_info; -static aic_option_callback_t ahd_linux_setup_rd_strm_info; -static aic_option_callback_t ahd_linux_setup_dv; static aic_option_callback_t ahd_linux_setup_iocell_info; -static int ahd_linux_next_unit(void); -static int aic79xx_setup(char *c); +static int aic79xx_setup(char *c); +static int ahd_linux_next_unit(void); /****************************** Inlines ***************************************/ -static __inline void ahd_schedule_completeq(struct ahd_softc *ahd); -static __inline struct ahd_linux_device* - ahd_linux_get_device(struct ahd_softc *ahd, u_int channel, - u_int target, u_int lun, int alloc); -static struct ahd_cmd *ahd_linux_run_complete_queue(struct ahd_softc *ahd); static __inline void ahd_linux_unmap_scb(struct ahd_softc*, struct scb*); -static __inline void -ahd_schedule_completeq(struct ahd_softc *ahd) -{ - if ((ahd->platform_data->flags & AHD_RUN_CMPLT_Q_TIMER) == 0) { - ahd->platform_data->flags |= AHD_RUN_CMPLT_Q_TIMER; - ahd->platform_data->completeq_timer.expires = jiffies; - add_timer(&ahd->platform_data->completeq_timer); - } -} - -static __inline struct ahd_linux_device* -ahd_linux_get_device(struct ahd_softc *ahd, u_int channel, u_int target, - u_int lun, int alloc) -{ - struct ahd_linux_target *targ; - struct ahd_linux_device *dev; - u_int target_offset; - - target_offset = target; - if (channel != 0) - target_offset += 8; - targ = ahd->platform_data->targets[target_offset]; - if (targ == NULL) { - if (alloc != 0) { - targ = ahd_linux_alloc_target(ahd, channel, target); - if (targ == NULL) - return (NULL); - } else - return (NULL); - } - dev = targ->devices[lun]; - if (dev == NULL && alloc != 0) - dev = ahd_linux_alloc_device(ahd, targ, lun); - return (dev); -} - -#define AHD_LINUX_MAX_RETURNED_ERRORS 4 -static struct ahd_cmd * -ahd_linux_run_complete_queue(struct ahd_softc *ahd) -{ - struct ahd_cmd *acmd; - u_long done_flags; - int with_errors; - - with_errors = 0; - ahd_done_lock(ahd, &done_flags); - while ((acmd = TAILQ_FIRST(&ahd->platform_data->completeq)) != NULL) { - Scsi_Cmnd *cmd; - - if (with_errors > AHD_LINUX_MAX_RETURNED_ERRORS) { - /* - * Linux uses stack recursion to requeue - * commands that need to be retried. Avoid - * blowing out the stack by "spoon feeding" - * commands that completed with error back - * the operating system in case they are going - * to be retried. "ick" - */ - ahd_schedule_completeq(ahd); - break; - } - TAILQ_REMOVE(&ahd->platform_data->completeq, - acmd, acmd_links.tqe); - cmd = &acmd_scsi_cmd(acmd); - cmd->host_scribble = NULL; - if (ahd_cmd_get_transaction_status(cmd) != DID_OK - || (cmd->result & 0xFF) != SCSI_STATUS_OK) - with_errors++; - - cmd->scsi_done(cmd); - } - ahd_done_unlock(ahd, &done_flags); - return (acmd); -} - static __inline void ahd_linux_unmap_scb(struct ahd_softc *ahd, struct scb *scb) { - Scsi_Cmnd *cmd; + struct scsi_cmnd *cmd; int direction; cmd = scb->io_ctx; @@ -624,51 +417,21 @@ ahd_linux_unmap_scb(struct ahd_softc *ahd, struct scb *scb) #define BUILD_SCSIID(ahd, cmd) \ ((((cmd)->device->id << TID_SHIFT) & TID) | (ahd)->our_id) -/************************ Host template entry points *************************/ -static int ahd_linux_detect(Scsi_Host_Template *); -static const char *ahd_linux_info(struct Scsi_Host *); -static int ahd_linux_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *)); -static int ahd_linux_slave_alloc(Scsi_Device *); -static int ahd_linux_slave_configure(Scsi_Device *); -static void ahd_linux_slave_destroy(Scsi_Device *); -#if defined(__i386__) -static int ahd_linux_biosparam(struct scsi_device*, - struct block_device*, sector_t, int[]); -#endif -static int ahd_linux_bus_reset(Scsi_Cmnd *); -static int ahd_linux_dev_reset(Scsi_Cmnd *); -static int ahd_linux_abort(Scsi_Cmnd *); - - /* * Try to detect an Adaptec 79XX controller. */ static int -ahd_linux_detect(Scsi_Host_Template *template) +ahd_linux_detect(struct scsi_host_template *template) { struct ahd_softc *ahd; int found; int error = 0; - /* - * Sanity checking of Linux SCSI data structures so - * that some of our hacks^H^H^H^H^Hassumptions aren't - * violated. - */ - if (offsetof(struct ahd_cmd_internal, end) - > offsetof(struct scsi_cmnd, host_scribble)) { - printf("ahd_linux_detect: SCSI data structures changed.\n"); - printf("ahd_linux_detect: Unable to attach\n"); - return (0); - } - -#ifdef MODULE /* * If we've been passed any parameters, process them now. */ if (aic79xx) aic79xx_setup(aic79xx); -#endif template->proc_name = "aic79xx"; @@ -695,7 +458,7 @@ ahd_linux_detect(Scsi_Host_Template *template) found++; } aic79xx_detect_complete++; - return 0; + return found; } /* @@ -730,10 +493,10 @@ ahd_linux_info(struct Scsi_Host *host) * Queue an SCB to the controller. */ static int -ahd_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *)) +ahd_linux_queue(struct scsi_cmnd * cmd, void (*scsi_done) (struct scsi_cmnd *)) { struct ahd_softc *ahd; - struct ahd_linux_device *dev; + struct ahd_linux_device *dev = scsi_transport_device_data(cmd->device); ahd = *(struct ahd_softc **)cmd->device->host->hostdata; @@ -743,8 +506,7 @@ ahd_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *)) * DV commands through so long as we are only frozen to * perform DV. */ - if (ahd->platform_data->qfrozen != 0 - && AHD_DV_CMD(cmd) == 0) { + if (ahd->platform_data->qfrozen != 0) { printf("%s: queue frozen\n", ahd_name(ahd)); return SCSI_MLQUEUE_HOST_BUSY; @@ -755,86 +517,142 @@ ahd_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *)) */ cmd->scsi_done = scsi_done; - dev = ahd_linux_get_device(ahd, cmd->device->channel, - cmd->device->id, cmd->device->lun, - /*alloc*/TRUE); - BUG_ON(dev == NULL); - cmd->result = CAM_REQ_INPROG << 16; return ahd_linux_run_command(ahd, dev, cmd); } -static int -ahd_linux_slave_alloc(Scsi_Device *device) +static inline struct scsi_target ** +ahd_linux_target_in_softc(struct scsi_target *starget) { - struct ahd_softc *ahd; + struct ahd_softc *ahd = + *((struct ahd_softc **)dev_to_shost(&starget->dev)->hostdata); + unsigned int target_offset; - ahd = *((struct ahd_softc **)device->host->hostdata); - if (bootverbose) - printf("%s: Slave Alloc %d\n", ahd_name(ahd), device->id); - return (0); + target_offset = starget->id; + if (starget->channel != 0) + target_offset += 8; + + return &ahd->platform_data->starget[target_offset]; } static int -ahd_linux_slave_configure(Scsi_Device *device) +ahd_linux_target_alloc(struct scsi_target *starget) { - struct ahd_softc *ahd; - struct ahd_linux_device *dev; - u_long flags; + struct ahd_softc *ahd = + *((struct ahd_softc **)dev_to_shost(&starget->dev)->hostdata); + unsigned long flags; + struct scsi_target **ahd_targp = ahd_linux_target_in_softc(starget); + struct ahd_linux_target *targ = scsi_transport_target_data(starget); + struct ahd_devinfo devinfo; + struct ahd_initiator_tinfo *tinfo; + struct ahd_tmode_tstate *tstate; + char channel = starget->channel + 'A'; - ahd = *((struct ahd_softc **)device->host->hostdata); - if (bootverbose) - printf("%s: Slave Configure %d\n", ahd_name(ahd), device->id); - ahd_midlayer_entrypoint_lock(ahd, &flags); - /* - * Since Linux has attached to the device, configure - * it so we don't free and allocate the device - * structure on every command. - */ - dev = ahd_linux_get_device(ahd, device->channel, - device->id, device->lun, - /*alloc*/TRUE); - if (dev != NULL) { - dev->flags &= ~AHD_DEV_UNCONFIGURED; - dev->flags |= AHD_DEV_SLAVE_CONFIGURED; - dev->scsi_device = device; - ahd_linux_device_queue_depth(ahd, dev); - } - ahd_midlayer_entrypoint_unlock(ahd, &flags); - return (0); + ahd_lock(ahd, &flags); + + BUG_ON(*ahd_targp != NULL); + + *ahd_targp = starget; + memset(targ, 0, sizeof(*targ)); + + tinfo = ahd_fetch_transinfo(ahd, channel, ahd->our_id, + starget->id, &tstate); + ahd_compile_devinfo(&devinfo, ahd->our_id, starget->id, + CAM_LUN_WILDCARD, channel, + ROLE_INITIATOR); + spi_min_period(starget) = AHD_SYNCRATE_MAX; /* We can do U320 */ + if ((ahd->bugs & AHD_PACED_NEGTABLE_BUG) != 0) + spi_max_offset(starget) = MAX_OFFSET_PACED_BUG; + else + spi_max_offset(starget) = MAX_OFFSET_PACED; + spi_max_width(starget) = ahd->features & AHD_WIDE; + + ahd_set_syncrate(ahd, &devinfo, 0, 0, 0, + AHD_TRANS_GOAL, /*paused*/FALSE); + ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, + AHD_TRANS_GOAL, /*paused*/FALSE); + ahd_unlock(ahd, &flags); + + return 0; } static void -ahd_linux_slave_destroy(Scsi_Device *device) +ahd_linux_target_destroy(struct scsi_target *starget) { - struct ahd_softc *ahd; - struct ahd_linux_device *dev; - u_long flags; + struct scsi_target **ahd_targp = ahd_linux_target_in_softc(starget); + + *ahd_targp = NULL; +} + +static int +ahd_linux_slave_alloc(struct scsi_device *sdev) +{ + struct ahd_softc *ahd = + *((struct ahd_softc **)sdev->host->hostdata); + struct scsi_target *starget = sdev->sdev_target; + struct ahd_linux_target *targ = scsi_transport_target_data(starget); + struct ahd_linux_device *dev; - ahd = *((struct ahd_softc **)device->host->hostdata); if (bootverbose) - printf("%s: Slave Destroy %d\n", ahd_name(ahd), device->id); - ahd_midlayer_entrypoint_lock(ahd, &flags); - dev = ahd_linux_get_device(ahd, device->channel, - device->id, device->lun, - /*alloc*/FALSE); + printf("%s: Slave Alloc %d\n", ahd_name(ahd), sdev->id); + + BUG_ON(targ->sdev[sdev->lun] != NULL); + + dev = scsi_transport_device_data(sdev); + memset(dev, 0, sizeof(*dev)); /* - * Filter out "silly" deletions of real devices by only - * deleting devices that have had slave_configure() - * called on them. All other devices that have not - * been configured will automatically be deleted by - * the refcounting process. + * We start out life using untagged + * transactions of which we allow one. */ - if (dev != NULL - && (dev->flags & AHD_DEV_SLAVE_CONFIGURED) != 0) { - dev->flags |= AHD_DEV_UNCONFIGURED; - if (dev->active == 0 - && (dev->flags & AHD_DEV_TIMER_ACTIVE) == 0) - ahd_linux_free_device(ahd, dev); - } - ahd_midlayer_entrypoint_unlock(ahd, &flags); + dev->openings = 1; + + /* + * Set maxtags to 0. This will be changed if we + * later determine that we are dealing with + * a tagged queuing capable device. + */ + dev->maxtags = 0; + + targ->sdev[sdev->lun] = sdev; + + return (0); +} + +static int +ahd_linux_slave_configure(struct scsi_device *sdev) +{ + struct ahd_softc *ahd; + + ahd = *((struct ahd_softc **)sdev->host->hostdata); + if (bootverbose) + printf("%s: Slave Configure %d\n", ahd_name(ahd), sdev->id); + + ahd_linux_device_queue_depth(sdev); + + /* Initial Domain Validation */ + if (!spi_initial_dv(sdev->sdev_target)) + spi_dv_device(sdev); + + return 0; +} + +static void +ahd_linux_slave_destroy(struct scsi_device *sdev) +{ + struct ahd_softc *ahd; + struct ahd_linux_device *dev = scsi_transport_device_data(sdev); + struct ahd_linux_target *targ = scsi_transport_target_data(sdev->sdev_target); + + ahd = *((struct ahd_softc **)sdev->host->hostdata); + if (bootverbose) + printf("%s: Slave Destroy %d\n", ahd_name(ahd), sdev->id); + + BUG_ON(dev->active); + + targ->sdev[sdev->lun] = NULL; + } #if defined(__i386__) @@ -887,373 +705,35 @@ ahd_linux_biosparam(struct scsi_device *sdev, struct block_device *bdev, * Abort the current SCSI command(s). */ static int -ahd_linux_abort(Scsi_Cmnd *cmd) +ahd_linux_abort(struct scsi_cmnd *cmd) { - struct ahd_softc *ahd; - struct ahd_cmd *acmd; - struct ahd_linux_device *dev; - struct scb *pending_scb; - u_long s; - u_int saved_scbptr; - u_int active_scbptr; - u_int last_phase; - u_int cdb_byte; - int retval; - int was_paused; - int paused; - int wait; - int disconnected; - ahd_mode_state saved_modes; + int error; - pending_scb = NULL; - paused = FALSE; - wait = FALSE; - ahd = *(struct ahd_softc **)cmd->device->host->hostdata; - acmd = (struct ahd_cmd *)cmd; - - printf("%s:%d:%d:%d: Attempting to abort cmd %p:", - ahd_name(ahd), cmd->device->channel, cmd->device->id, - cmd->device->lun, cmd); - for (cdb_byte = 0; cdb_byte < cmd->cmd_len; cdb_byte++) - printf(" 0x%x", cmd->cmnd[cdb_byte]); - printf("\n"); - - /* - * In all versions of Linux, we have to work around - * a major flaw in how the mid-layer is locked down - * if we are to sleep successfully in our error handler - * while allowing our interrupt handler to run. Since - * the midlayer acquires either the io_request_lock or - * our lock prior to calling us, we must use the - * spin_unlock_irq() method for unlocking our lock. - * This will force interrupts to be enabled on the - * current CPU. Since the EH thread should not have - * been running with CPU interrupts disabled other than - * by acquiring either the io_request_lock or our own - * lock, this *should* be safe. - */ - ahd_midlayer_entrypoint_lock(ahd, &s); - - /* - * First determine if we currently own this command. - * Start by searching the device queue. If not found - * there, check the pending_scb list. If not found - * at all, and the system wanted us to just abort the - * command, return success. - */ - dev = ahd_linux_get_device(ahd, cmd->device->channel, - cmd->device->id, cmd->device->lun, - /*alloc*/FALSE); - - if (dev == NULL) { - /* - * No target device for this command exists, - * so we must not still own the command. - */ - printf("%s:%d:%d:%d: Is not an active device\n", - ahd_name(ahd), cmd->device->channel, cmd->device->id, - cmd->device->lun); - retval = SUCCESS; - goto no_cmd; - } - - /* - * See if we can find a matching cmd in the pending list. - */ - LIST_FOREACH(pending_scb, &ahd->pending_scbs, pending_links) { - if (pending_scb->io_ctx == cmd) - break; - } - - if (pending_scb == NULL) { - printf("%s:%d:%d:%d: Command not found\n", - ahd_name(ahd), cmd->device->channel, cmd->device->id, - cmd->device->lun); - goto no_cmd; - } - - if ((pending_scb->flags & SCB_RECOVERY_SCB) != 0) { - /* - * We can't queue two recovery actions using the same SCB - */ - retval = FAILED; - goto done; - } - - /* - * Ensure that the card doesn't do anything - * behind our back. Also make sure that we - * didn't "just" miss an interrupt that would - * affect this cmd. - */ - was_paused = ahd_is_paused(ahd); - ahd_pause_and_flushwork(ahd); - paused = TRUE; - - if ((pending_scb->flags & SCB_ACTIVE) == 0) { - printf("%s:%d:%d:%d: Command already completed\n", - ahd_name(ahd), cmd->device->channel, cmd->device->id, - cmd->device->lun); - goto no_cmd; - } - - printf("%s: At time of recovery, card was %spaused\n", - ahd_name(ahd), was_paused ? "" : "not "); - ahd_dump_card_state(ahd); - - disconnected = TRUE; - if (ahd_search_qinfifo(ahd, cmd->device->id, cmd->device->channel + 'A', - cmd->device->lun, SCB_GET_TAG(pending_scb), - ROLE_INITIATOR, CAM_REQ_ABORTED, - SEARCH_COMPLETE) > 0) { - printf("%s:%d:%d:%d: Cmd aborted from QINFIFO\n", - ahd_name(ahd), cmd->device->channel, cmd->device->id, - cmd->device->lun); - retval = SUCCESS; - goto done; - } - - saved_modes = ahd_save_modes(ahd); - ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); - last_phase = ahd_inb(ahd, LASTPHASE); - saved_scbptr = ahd_get_scbptr(ahd); - active_scbptr = saved_scbptr; - if (disconnected && (ahd_inb(ahd, SEQ_FLAGS) & NOT_IDENTIFIED) == 0) { - struct scb *bus_scb; - - bus_scb = ahd_lookup_scb(ahd, active_scbptr); - if (bus_scb == pending_scb) - disconnected = FALSE; - } - - /* - * At this point, pending_scb is the scb associated with the - * passed in command. That command is currently active on the - * bus or is in the disconnected state. - */ - if (last_phase != P_BUSFREE - && SCB_GET_TAG(pending_scb) == active_scbptr) { - - /* - * We're active on the bus, so assert ATN - * and hope that the target responds. - */ - pending_scb = ahd_lookup_scb(ahd, active_scbptr); - pending_scb->flags |= SCB_RECOVERY_SCB|SCB_ABORT; - ahd_outb(ahd, MSG_OUT, HOST_MSG); - ahd_outb(ahd, SCSISIGO, last_phase|ATNO); - printf("%s:%d:%d:%d: Device is active, asserting ATN\n", - ahd_name(ahd), cmd->device->channel, - cmd->device->id, cmd->device->lun); - wait = TRUE; - } else if (disconnected) { - - /* - * Actually re-queue this SCB in an attempt - * to select the device before it reconnects. - */ - pending_scb->flags |= SCB_RECOVERY_SCB|SCB_ABORT; - ahd_set_scbptr(ahd, SCB_GET_TAG(pending_scb)); - pending_scb->hscb->cdb_len = 0; - pending_scb->hscb->task_attribute = 0; - pending_scb->hscb->task_management = SIU_TASKMGMT_ABORT_TASK; - - if ((pending_scb->flags & SCB_PACKETIZED) != 0) { - /* - * Mark the SCB has having an outstanding - * task management function. Should the command - * complete normally before the task management - * function can be sent, the host will be notified - * to abort our requeued SCB. - */ - ahd_outb(ahd, SCB_TASK_MANAGEMENT, - pending_scb->hscb->task_management); - } else { - /* - * If non-packetized, set the MK_MESSAGE control - * bit indicating that we desire to send a message. - * We also set the disconnected flag since there is - * no guarantee that our SCB control byte matches - * the version on the card. We don't want the - * sequencer to abort the command thinking an - * unsolicited reselection occurred. - */ - pending_scb->hscb->control |= MK_MESSAGE|DISCONNECTED; - - /* - * The sequencer will never re-reference the - * in-core SCB. To make sure we are notified - * during reslection, set the MK_MESSAGE flag in - * the card's copy of the SCB. - */ - ahd_outb(ahd, SCB_CONTROL, - ahd_inb(ahd, SCB_CONTROL)|MK_MESSAGE); - } - - /* - * Clear out any entries in the QINFIFO first - * so we are the next SCB for this target - * to run. - */ - ahd_search_qinfifo(ahd, cmd->device->id, - cmd->device->channel + 'A', cmd->device->lun, - SCB_LIST_NULL, ROLE_INITIATOR, - CAM_REQUEUE_REQ, SEARCH_COMPLETE); - ahd_qinfifo_requeue_tail(ahd, pending_scb); - ahd_set_scbptr(ahd, saved_scbptr); - ahd_print_path(ahd, pending_scb); - printf("Device is disconnected, re-queuing SCB\n"); - wait = TRUE; - } else { - printf("%s:%d:%d:%d: Unable to deliver message\n", - ahd_name(ahd), cmd->device->channel, - cmd->device->id, cmd->device->lun); - retval = FAILED; - goto done; - } - -no_cmd: - /* - * Our assumption is that if we don't have the command, no - * recovery action was required, so we return success. Again, - * the semantics of the mid-layer recovery engine are not - * well defined, so this may change in time. - */ - retval = SUCCESS; -done: - if (paused) - ahd_unpause(ahd); - if (wait) { - struct timer_list timer; - int ret; - - pending_scb->platform_data->flags |= AHD_SCB_UP_EH_SEM; - spin_unlock_irq(&ahd->platform_data->spin_lock); - init_timer(&timer); - timer.data = (u_long)pending_scb; - timer.expires = jiffies + (5 * HZ); - timer.function = ahd_linux_sem_timeout; - add_timer(&timer); - printf("Recovery code sleeping\n"); - down(&ahd->platform_data->eh_sem); - printf("Recovery code awake\n"); - ret = del_timer_sync(&timer); - if (ret == 0) { - printf("Timer Expired\n"); - retval = FAILED; - } - spin_lock_irq(&ahd->platform_data->spin_lock); - } - ahd_linux_run_complete_queue(ahd); - ahd_midlayer_entrypoint_unlock(ahd, &s); - return (retval); -} - - -static void -ahd_linux_dev_reset_complete(Scsi_Cmnd *cmd) -{ - free(cmd, M_DEVBUF); + error = ahd_linux_queue_recovery_cmd(cmd, SCB_ABORT); + if (error != 0) + printf("aic79xx_abort returns 0x%x\n", error); + return error; } /* * Attempt to send a target reset message to the device that timed out. */ static int -ahd_linux_dev_reset(Scsi_Cmnd *cmd) +ahd_linux_dev_reset(struct scsi_cmnd *cmd) { - struct ahd_softc *ahd; - struct scsi_cmnd *recovery_cmd; - struct ahd_linux_device *dev; - struct ahd_initiator_tinfo *tinfo; - struct ahd_tmode_tstate *tstate; - struct scb *scb; - struct hardware_scb *hscb; - u_long s; - struct timer_list timer; - int retval; + int error; - ahd = *(struct ahd_softc **)cmd->device->host->hostdata; - recovery_cmd = malloc(sizeof(struct scsi_cmnd), M_DEVBUF, M_WAITOK); - if (!recovery_cmd) - return (FAILED); - memset(recovery_cmd, 0, sizeof(struct scsi_cmnd)); - recovery_cmd->device = cmd->device; - recovery_cmd->scsi_done = ahd_linux_dev_reset_complete; -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) - printf("%s:%d:%d:%d: Device reset called for cmd %p\n", - ahd_name(ahd), cmd->device->channel, cmd->device->id, - cmd->device->lun, cmd); -#endif - ahd_lock(ahd, &s); - - dev = ahd_linux_get_device(ahd, cmd->device->channel, cmd->device->id, - cmd->device->lun, /*alloc*/FALSE); - if (dev == NULL) { - ahd_unlock(ahd, &s); - kfree(recovery_cmd); - return (FAILED); - } - if ((scb = ahd_get_scb(ahd, AHD_NEVER_COL_IDX)) == NULL) { - ahd_unlock(ahd, &s); - kfree(recovery_cmd); - return (FAILED); - } - tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id, - cmd->device->id, &tstate); - recovery_cmd->result = CAM_REQ_INPROG << 16; - recovery_cmd->host_scribble = (char *)scb; - scb->io_ctx = recovery_cmd; - scb->platform_data->dev = dev; - scb->sg_count = 0; - ahd_set_residual(scb, 0); - ahd_set_sense_residual(scb, 0); - hscb = scb->hscb; - hscb->control = 0; - hscb->scsiid = BUILD_SCSIID(ahd, cmd); - hscb->lun = cmd->device->lun; - hscb->cdb_len = 0; - hscb->task_management = SIU_TASKMGMT_LUN_RESET; - scb->flags |= SCB_DEVICE_RESET|SCB_RECOVERY_SCB|SCB_ACTIVE; - if ((tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0) { - scb->flags |= SCB_PACKETIZED; - } else { - hscb->control |= MK_MESSAGE; - } - dev->openings--; - dev->active++; - dev->commands_issued++; - LIST_INSERT_HEAD(&ahd->pending_scbs, scb, pending_links); - ahd_queue_scb(ahd, scb); - - scb->platform_data->flags |= AHD_SCB_UP_EH_SEM; - ahd_unlock(ahd, &s); - init_timer(&timer); - timer.data = (u_long)scb; - timer.expires = jiffies + (5 * HZ); - timer.function = ahd_linux_sem_timeout; - add_timer(&timer); - printf("Recovery code sleeping\n"); - down(&ahd->platform_data->eh_sem); - printf("Recovery code awake\n"); - retval = SUCCESS; - if (del_timer_sync(&timer) == 0) { - printf("Timer Expired\n"); - retval = FAILED; - } - ahd_lock(ahd, &s); - ahd_linux_run_complete_queue(ahd); - ahd_unlock(ahd, &s); - printf("%s: Device reset returning 0x%x\n", ahd_name(ahd), retval); - return (retval); + error = ahd_linux_queue_recovery_cmd(cmd, SCB_DEVICE_RESET); + if (error != 0) + printf("aic79xx_dev_reset returns 0x%x\n", error); + return error; } /* * Reset the SCSI bus. */ static int -ahd_linux_bus_reset(Scsi_Cmnd *cmd) +ahd_linux_bus_reset(struct scsi_cmnd *cmd) { struct ahd_softc *ahd; u_long s; @@ -1268,7 +748,6 @@ ahd_linux_bus_reset(Scsi_Cmnd *cmd) ahd_lock(ahd, &s); found = ahd_reset_channel(ahd, cmd->device->channel + 'A', /*initiate reset*/TRUE); - ahd_linux_run_complete_queue(ahd); ahd_unlock(ahd, &s); if (bootverbose) @@ -1278,7 +757,7 @@ ahd_linux_bus_reset(Scsi_Cmnd *cmd) return (SUCCESS); } -Scsi_Host_Template aic79xx_driver_template = { +struct scsi_host_template aic79xx_driver_template = { .module = THIS_MODULE, .name = "aic79xx", .proc_info = ahd_linux_proc_info, @@ -1297,6 +776,8 @@ Scsi_Host_Template aic79xx_driver_template = { .slave_alloc = ahd_linux_slave_alloc, .slave_configure = ahd_linux_slave_configure, .slave_destroy = ahd_linux_slave_destroy, + .target_alloc = ahd_linux_target_alloc, + .target_destroy = ahd_linux_target_destroy, }; /******************************** Bus DMA *************************************/ @@ -1338,36 +819,10 @@ int ahd_dmamem_alloc(struct ahd_softc *ahd, bus_dma_tag_t dmat, void** vaddr, int flags, bus_dmamap_t *mapp) { - bus_dmamap_t map; - - map = malloc(sizeof(*map), M_DEVBUF, M_NOWAIT); - if (map == NULL) - return (ENOMEM); - /* - * Although we can dma data above 4GB, our - * "consistent" memory is below 4GB for - * space efficiency reasons (only need a 4byte - * address). For this reason, we have to reset - * our dma mask when doing allocations. - */ - if (ahd->dev_softc != NULL) - if (pci_set_dma_mask(ahd->dev_softc, 0xFFFFFFFF)) { - printk(KERN_WARNING "aic79xx: No suitable DMA available.\n"); - kfree(map); - return (ENODEV); - } *vaddr = pci_alloc_consistent(ahd->dev_softc, - dmat->maxsize, &map->bus_addr); - if (ahd->dev_softc != NULL) - if (pci_set_dma_mask(ahd->dev_softc, - ahd->platform_data->hw_dma_mask)) { - printk(KERN_WARNING "aic79xx: No suitable DMA available.\n"); - kfree(map); - return (ENODEV); - } + dmat->maxsize, mapp); if (*vaddr == NULL) return (ENOMEM); - *mapp = map; return(0); } @@ -1376,7 +831,7 @@ ahd_dmamem_free(struct ahd_softc *ahd, bus_dma_tag_t dmat, void* vaddr, bus_dmamap_t map) { pci_free_consistent(ahd->dev_softc, dmat->maxsize, - vaddr, map->bus_addr); + vaddr, map); } int @@ -1390,7 +845,7 @@ ahd_dmamap_load(struct ahd_softc *ahd, bus_dma_tag_t dmat, bus_dmamap_t map, */ bus_dma_segment_t stack_sg; - stack_sg.ds_addr = map->bus_addr; + stack_sg.ds_addr = map; stack_sg.ds_len = dmat->maxsize; cb(cb_arg, &stack_sg, /*nseg*/1, /*error*/0); return (0); @@ -1399,11 +854,6 @@ ahd_dmamap_load(struct ahd_softc *ahd, bus_dma_tag_t dmat, bus_dmamap_t map, void ahd_dmamap_destroy(struct ahd_softc *ahd, bus_dma_tag_t dmat, bus_dmamap_t map) { - /* - * The map may is NULL in our < 2.3.X implementation. - */ - if (map != NULL) - free(map, M_DEVBUF); } int @@ -1467,41 +917,6 @@ ahd_softc_comp(struct ahd_softc *lahd, struct ahd_softc *rahd) return (value); } -static void -ahd_linux_setup_tag_info(u_long arg, int instance, int targ, int32_t value) -{ - - if ((instance >= 0) && (targ >= 0) - && (instance < NUM_ELEMENTS(aic79xx_tag_info)) - && (targ < AHD_NUM_TARGETS)) { - aic79xx_tag_info[instance].tag_commands[targ] = value & 0x1FF; - if (bootverbose) - printf("tag_info[%d:%d] = %d\n", instance, targ, value); - } -} - -static void -ahd_linux_setup_rd_strm_info(u_long arg, int instance, int targ, int32_t value) -{ - if ((instance >= 0) - && (instance < NUM_ELEMENTS(aic79xx_rd_strm_info))) { - aic79xx_rd_strm_info[instance] = value & 0xFFFF; - if (bootverbose) - printf("rd_strm[%d] = 0x%x\n", instance, value); - } -} - -static void -ahd_linux_setup_dv(u_long arg, int instance, int targ, int32_t value) -{ - if ((instance >= 0) - && (instance < NUM_ELEMENTS(aic79xx_dv_settings))) { - aic79xx_dv_settings[instance] = value; - if (bootverbose) - printf("dv[%d] = %d\n", instance, value); - } -} - static void ahd_linux_setup_iocell_info(u_long index, int instance, int targ, int32_t value) { @@ -1532,6 +947,19 @@ ahd_linux_setup_tag_info_global(char *p) } } +static void +ahd_linux_setup_tag_info(u_long arg, int instance, int targ, int32_t value) +{ + + if ((instance >= 0) && (targ >= 0) + && (instance < NUM_ELEMENTS(aic79xx_tag_info)) + && (targ < AHD_NUM_TARGETS)) { + aic79xx_tag_info[instance].tag_commands[targ] = value & 0x1FF; + if (bootverbose) + printf("tag_info[%d:%d] = %d\n", instance, targ, value); + } +} + /* * Handle Linux boot parameters. This routine allows for assigning a value * to a parameter with a ':' between the parameter and the value. @@ -1561,8 +989,6 @@ aic79xx_setup(char *s) { "seltime", &aic79xx_seltime }, { "tag_info", NULL }, { "global_tag_depth", NULL}, - { "rd_strm", NULL }, - { "dv", NULL }, { "slewrate", NULL }, { "precomp", NULL }, { "amplitude", NULL }, @@ -1593,12 +1019,6 @@ aic79xx_setup(char *s) } else if (strncmp(p, "tag_info", n) == 0) { s = aic_parse_brace_option("tag_info", p + n, end, 2, ahd_linux_setup_tag_info, 0); - } else if (strncmp(p, "rd_strm", n) == 0) { - s = aic_parse_brace_option("rd_strm", p + n, end, - 1, ahd_linux_setup_rd_strm_info, 0); - } else if (strncmp(p, "dv", n) == 0) { - s = aic_parse_brace_option("dv", p + n, end, 1, - ahd_linux_setup_dv, 0); } else if (strncmp(p, "slewrate", n) == 0) { s = aic_parse_brace_option("slewrate", p + n, end, 1, ahd_linux_setup_iocell_info, @@ -1627,13 +1047,12 @@ __setup("aic79xx=", aic79xx_setup); uint32_t aic79xx_verbose; int -ahd_linux_register_host(struct ahd_softc *ahd, Scsi_Host_Template *template) +ahd_linux_register_host(struct ahd_softc *ahd, struct scsi_host_template *template) { char buf[80]; struct Scsi_Host *host; char *new_name; u_long s; - u_long target; template->name = ahd->description; host = scsi_host_alloc(template, sizeof(struct ahd_softc *)); @@ -1661,47 +1080,12 @@ ahd_linux_register_host(struct ahd_softc *ahd, Scsi_Host_Template *template) ahd_set_name(ahd, new_name); } host->unique_id = ahd->unit; - ahd_linux_setup_user_rd_strm_settings(ahd); ahd_linux_initialize_scsi_bus(ahd); - ahd_unlock(ahd, &s); - ahd->platform_data->dv_pid = kernel_thread(ahd_linux_dv_thread, ahd, 0); - ahd_lock(ahd, &s); - if (ahd->platform_data->dv_pid < 0) { - printf("%s: Failed to create DV thread, error= %d\n", - ahd_name(ahd), ahd->platform_data->dv_pid); - return (-ahd->platform_data->dv_pid); - } - /* - * Initially allocate *all* of our linux target objects - * so that the DV thread will scan them all in parallel - * just after driver initialization. Any device that - * does not exist will have its target object destroyed - * by the selection timeout handler. In the case of a - * device that appears after the initial DV scan, async - * negotiation will occur for the first command, and DV - * will comence should that first command be successful. - */ - for (target = 0; target < host->max_id; target++) { - - /* - * Skip our own ID. Some Compaq/HP storage devices - * have enclosure management devices that respond to - * single bit selection (i.e. selecting ourselves). - * It is expected that either an external application - * or a modified kernel will be used to probe this - * ID if it is appropriate. To accommodate these - * installations, ahc_linux_alloc_target() will allocate - * for our ID if asked to do so. - */ - if (target == ahd->our_id) - continue; - - ahd_linux_alloc_target(ahd, 0, target); - } ahd_intr_enable(ahd, TRUE); - ahd_linux_start_dv(ahd); ahd_unlock(ahd, &s); + host->transportt = ahd_linux_transport_template; + scsi_add_host(host, &ahd->dev_softc->dev); /* XXX handle failure */ scsi_scan_host(host); return (0); @@ -1798,18 +1182,9 @@ ahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg) if (ahd->platform_data == NULL) return (ENOMEM); memset(ahd->platform_data, 0, sizeof(struct ahd_platform_data)); - TAILQ_INIT(&ahd->platform_data->completeq); ahd->platform_data->irq = AHD_LINUX_NOIRQ; - ahd->platform_data->hw_dma_mask = 0xFFFFFFFF; ahd_lockinit(ahd); - ahd_done_lockinit(ahd); - init_timer(&ahd->platform_data->completeq_timer); - ahd->platform_data->completeq_timer.data = (u_long)ahd; - ahd->platform_data->completeq_timer.function = - (ahd_linux_callback_t *)ahd_linux_thread_run_complete_queue; init_MUTEX_LOCKED(&ahd->platform_data->eh_sem); - init_MUTEX_LOCKED(&ahd->platform_data->dv_sem); - init_MUTEX_LOCKED(&ahd->platform_data->dv_cmd_sem); ahd->seltime = (aic79xx_seltime & 0x3) << 4; return (0); } @@ -1817,13 +1192,10 @@ ahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg) void ahd_platform_free(struct ahd_softc *ahd) { - struct ahd_linux_target *targ; - struct ahd_linux_device *dev; + struct scsi_target *starget; int i, j; if (ahd->platform_data != NULL) { - del_timer_sync(&ahd->platform_data->completeq_timer); - ahd_linux_kill_dv_thread(ahd); if (ahd->platform_data->host != NULL) { scsi_remove_host(ahd->platform_data->host); scsi_host_put(ahd->platform_data->host); @@ -1831,22 +1203,16 @@ ahd_platform_free(struct ahd_softc *ahd) /* destroy all of the device and target objects */ for (i = 0; i < AHD_NUM_TARGETS; i++) { - targ = ahd->platform_data->targets[i]; - if (targ != NULL) { - /* Keep target around through the loop. */ - targ->refcount++; + starget = ahd->platform_data->starget[i]; + if (starget != NULL) { for (j = 0; j < AHD_NUM_LUNS; j++) { - - if (targ->devices[j] == NULL) + struct ahd_linux_target *targ = + scsi_transport_target_data(starget); + if (targ->sdev[j] == NULL) continue; - dev = targ->devices[j]; - ahd_linux_free_device(ahd, dev); + targ->sdev[j] = NULL; } - /* - * Forcibly free the target now that - * all devices are gone. - */ - ahd_linux_free_target(ahd, targ); + ahd->platform_data->starget[i] = NULL; } } @@ -1901,13 +1267,22 @@ void ahd_platform_set_tags(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, ahd_queue_alg alg) { + struct scsi_target *starget; + struct ahd_linux_target *targ; struct ahd_linux_device *dev; + struct scsi_device *sdev; int was_queuing; int now_queuing; - dev = ahd_linux_get_device(ahd, devinfo->channel - 'A', - devinfo->target, - devinfo->lun, /*alloc*/FALSE); + starget = ahd->platform_data->starget[devinfo->target]; + targ = scsi_transport_target_data(starget); + BUG_ON(targ == NULL); + sdev = targ->sdev[devinfo->lun]; + if (sdev == NULL) + return; + + dev = scsi_transport_device_data(sdev); + if (dev == NULL) return; was_queuing = dev->flags & (AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED); @@ -1961,30 +1336,28 @@ ahd_platform_set_tags(struct ahd_softc *ahd, struct ahd_devinfo *devinfo, dev->openings = 1 - dev->active; } - if (dev->scsi_device != NULL) { - switch ((dev->flags & (AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED))) { - case AHD_DEV_Q_BASIC: - scsi_adjust_queue_depth(dev->scsi_device, - MSG_SIMPLE_TASK, - dev->openings + dev->active); - break; - case AHD_DEV_Q_TAGGED: - scsi_adjust_queue_depth(dev->scsi_device, - MSG_ORDERED_TASK, - dev->openings + dev->active); - break; - default: - /* - * We allow the OS to queue 2 untagged transactions to - * us at any time even though we can only execute them - * serially on the controller/device. This should - * remove some latency. - */ - scsi_adjust_queue_depth(dev->scsi_device, - /*NON-TAGGED*/0, - /*queue depth*/2); - break; - } + switch ((dev->flags & (AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED))) { + case AHD_DEV_Q_BASIC: + scsi_adjust_queue_depth(sdev, + MSG_SIMPLE_TASK, + dev->openings + dev->active); + break; + case AHD_DEV_Q_TAGGED: + scsi_adjust_queue_depth(sdev, + MSG_ORDERED_TASK, + dev->openings + dev->active); + break; + default: + /* + * We allow the OS to queue 2 untagged transactions to + * us at any time even though we can only execute them + * serially on the controller/device. This should + * remove some latency. + */ + scsi_adjust_queue_depth(sdev, + /*NON-TAGGED*/0, + /*queue depth*/2); + break; } } @@ -1995,1339 +1368,6 @@ ahd_platform_abort_scbs(struct ahd_softc *ahd, int target, char channel, return 0; } -static void -ahd_linux_thread_run_complete_queue(struct ahd_softc *ahd) -{ - u_long flags; - - ahd_lock(ahd, &flags); - del_timer(&ahd->platform_data->completeq_timer); - ahd->platform_data->flags &= ~AHD_RUN_CMPLT_Q_TIMER; - ahd_linux_run_complete_queue(ahd); - ahd_unlock(ahd, &flags); -} - -static void -ahd_linux_start_dv(struct ahd_softc *ahd) -{ - - /* - * Freeze the simq and signal ahd_linux_queue to not let any - * more commands through - */ - if ((ahd->platform_data->flags & AHD_DV_ACTIVE) == 0) { -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) - printf("%s: Starting DV\n", ahd_name(ahd)); -#endif - - ahd->platform_data->flags |= AHD_DV_ACTIVE; - ahd_freeze_simq(ahd); - - /* Wake up the DV kthread */ - up(&ahd->platform_data->dv_sem); - } -} - -static int -ahd_linux_dv_thread(void *data) -{ - struct ahd_softc *ahd; - int target; - u_long s; - - ahd = (struct ahd_softc *)data; - -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) - printf("In DV Thread\n"); -#endif - - /* - * Complete thread creation. - */ - lock_kernel(); - - daemonize("ahd_dv_%d", ahd->unit); - current->flags |= PF_FREEZE; - - unlock_kernel(); - - while (1) { - /* - * Use down_interruptible() rather than down() to - * avoid inclusion in the load average. - */ - down_interruptible(&ahd->platform_data->dv_sem); - - /* Check to see if we've been signaled to exit */ - ahd_lock(ahd, &s); - if ((ahd->platform_data->flags & AHD_DV_SHUTDOWN) != 0) { - ahd_unlock(ahd, &s); - break; - } - ahd_unlock(ahd, &s); - -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) - printf("%s: Beginning Domain Validation\n", - ahd_name(ahd)); -#endif - - /* - * Wait for any pending commands to drain before proceeding. - */ - ahd_lock(ahd, &s); - while (LIST_FIRST(&ahd->pending_scbs) != NULL) { - ahd->platform_data->flags |= AHD_DV_WAIT_SIMQ_EMPTY; - ahd_unlock(ahd, &s); - down_interruptible(&ahd->platform_data->dv_sem); - ahd_lock(ahd, &s); - } - - /* - * Wait for the SIMQ to be released so that DV is the - * only reason the queue is frozen. - */ - while (AHD_DV_SIMQ_FROZEN(ahd) == 0) { - ahd->platform_data->flags |= AHD_DV_WAIT_SIMQ_RELEASE; - ahd_unlock(ahd, &s); - down_interruptible(&ahd->platform_data->dv_sem); - ahd_lock(ahd, &s); - } - ahd_unlock(ahd, &s); - - for (target = 0; target < AHD_NUM_TARGETS; target++) - ahd_linux_dv_target(ahd, target); - - ahd_lock(ahd, &s); - ahd->platform_data->flags &= ~AHD_DV_ACTIVE; - ahd_unlock(ahd, &s); - - /* - * Release the SIMQ so that normal commands are - * allowed to continue on the bus. - */ - ahd_release_simq(ahd); - } - up(&ahd->platform_data->eh_sem); - return (0); -} - -static void -ahd_linux_kill_dv_thread(struct ahd_softc *ahd) -{ - u_long s; - - ahd_lock(ahd, &s); - if (ahd->platform_data->dv_pid != 0) { - ahd->platform_data->flags |= AHD_DV_SHUTDOWN; - ahd_unlock(ahd, &s); - up(&ahd->platform_data->dv_sem); - - /* - * Use the eh_sem as an indicator that the - * dv thread is exiting. Note that the dv - * thread must still return after performing - * the up on our semaphore before it has - * completely exited this module. Unfortunately, - * there seems to be no easy way to wait for the - * exit of a thread for which you are not the - * parent (dv threads are parented by init). - * Cross your fingers... - */ - down(&ahd->platform_data->eh_sem); - - /* - * Mark the dv thread as already dead. This - * avoids attempting to kill it a second time. - * This is necessary because we must kill the - * DV thread before calling ahd_free() in the - * module shutdown case to avoid bogus locking - * in the SCSI mid-layer, but we ahd_free() is - * called without killing the DV thread in the - * instance detach case, so ahd_platform_free() - * calls us again to verify that the DV thread - * is dead. - */ - ahd->platform_data->dv_pid = 0; - } else { - ahd_unlock(ahd, &s); - } -} - -#define AHD_LINUX_DV_INQ_SHORT_LEN 36 -#define AHD_LINUX_DV_INQ_LEN 256 -#define AHD_LINUX_DV_TIMEOUT (HZ / 4) - -#define AHD_SET_DV_STATE(ahd, targ, newstate) \ - ahd_set_dv_state(ahd, targ, newstate, __LINE__) - -static __inline void -ahd_set_dv_state(struct ahd_softc *ahd, struct ahd_linux_target *targ, - ahd_dv_state newstate, u_int line) -{ - ahd_dv_state oldstate; - - oldstate = targ->dv_state; -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) - printf("%s:%d: Going from state %d to state %d\n", - ahd_name(ahd), line, oldstate, newstate); -#endif - - if (oldstate == newstate) - targ->dv_state_retry++; - else - targ->dv_state_retry = 0; - targ->dv_state = newstate; -} - -static void -ahd_linux_dv_target(struct ahd_softc *ahd, u_int target_offset) -{ - struct ahd_devinfo devinfo; - struct ahd_linux_target *targ; - struct scsi_cmnd *cmd; - struct scsi_device *scsi_dev; - struct scsi_sense_data *sense; - uint8_t *buffer; - u_long s; - u_int timeout; - int echo_size; - - sense = NULL; - buffer = NULL; - echo_size = 0; - ahd_lock(ahd, &s); - targ = ahd->platform_data->targets[target_offset]; - if (targ == NULL || (targ->flags & AHD_DV_REQUIRED) == 0) { - ahd_unlock(ahd, &s); - return; - } - ahd_compile_devinfo(&devinfo, ahd->our_id, targ->target, /*lun*/0, - targ->channel + 'A', ROLE_INITIATOR); -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - ahd_print_devinfo(ahd, &devinfo); - printf("Performing DV\n"); - } -#endif - - ahd_unlock(ahd, &s); - - cmd = malloc(sizeof(struct scsi_cmnd), M_DEVBUF, M_WAITOK); - scsi_dev = malloc(sizeof(struct scsi_device), M_DEVBUF, M_WAITOK); - scsi_dev->host = ahd->platform_data->host; - scsi_dev->id = devinfo.target; - scsi_dev->lun = devinfo.lun; - scsi_dev->channel = devinfo.channel - 'A'; - ahd->platform_data->dv_scsi_dev = scsi_dev; - - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_INQ_SHORT_ASYNC); - - while (targ->dv_state != AHD_DV_STATE_EXIT) { - timeout = AHD_LINUX_DV_TIMEOUT; - switch (targ->dv_state) { - case AHD_DV_STATE_INQ_SHORT_ASYNC: - case AHD_DV_STATE_INQ_ASYNC: - case AHD_DV_STATE_INQ_ASYNC_VERIFY: - /* - * Set things to async narrow to reduce the - * chance that the INQ will fail. - */ - ahd_lock(ahd, &s); - ahd_set_syncrate(ahd, &devinfo, 0, 0, 0, - AHD_TRANS_GOAL, /*paused*/FALSE); - ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, - AHD_TRANS_GOAL, /*paused*/FALSE); - ahd_unlock(ahd, &s); - timeout = 10 * HZ; - targ->flags &= ~AHD_INQ_VALID; - /* FALLTHROUGH */ - case AHD_DV_STATE_INQ_VERIFY: - { - u_int inq_len; - - if (targ->dv_state == AHD_DV_STATE_INQ_SHORT_ASYNC) - inq_len = AHD_LINUX_DV_INQ_SHORT_LEN; - else - inq_len = targ->inq_data->additional_length + 5; - ahd_linux_dv_inq(ahd, cmd, &devinfo, targ, inq_len); - break; - } - case AHD_DV_STATE_TUR: - case AHD_DV_STATE_BUSY: - timeout = 5 * HZ; - ahd_linux_dv_tur(ahd, cmd, &devinfo); - break; - case AHD_DV_STATE_REBD: - ahd_linux_dv_rebd(ahd, cmd, &devinfo, targ); - break; - case AHD_DV_STATE_WEB: - ahd_linux_dv_web(ahd, cmd, &devinfo, targ); - break; - - case AHD_DV_STATE_REB: - ahd_linux_dv_reb(ahd, cmd, &devinfo, targ); - break; - - case AHD_DV_STATE_SU: - ahd_linux_dv_su(ahd, cmd, &devinfo, targ); - timeout = 50 * HZ; - break; - - default: - ahd_print_devinfo(ahd, &devinfo); - printf("Unknown DV state %d\n", targ->dv_state); - goto out; - } - - /* Queue the command and wait for it to complete */ - /* Abuse eh_timeout in the scsi_cmnd struct for our purposes */ - init_timer(&cmd->eh_timeout); -#ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) - /* - * All of the printfs during negotiation - * really slow down the negotiation. - * Add a bit of time just to be safe. - */ - timeout += HZ; -#endif - scsi_add_timer(cmd, timeout, ahd_linux_dv_timeout); - /* - * In 2.5.X, it is assumed that all calls from the - * "midlayer" (which we are emulating) will have the - * ahd host lock held. For other kernels, the - * io_request_lock must be held. - */ -#if AHD_SCSI_HAS_HOST_LOCK != 0 - ahd_lock(ahd, &s); -#else - spin_lock_irqsave(&io_request_lock, s); -#endif - ahd_linux_queue(cmd, ahd_linux_dv_complete); -#if AHD_SCSI_HAS_HOST_LOCK != 0 - ahd_unlock(ahd, &s); -#else - spin_unlock_irqrestore(&io_request_lock, s); -#endif - down_interruptible(&ahd->platform_data->dv_cmd_sem); - /* - * Wait for the SIMQ to be released so that DV is the - * only reason the queue is frozen. - */ - ahd_lock(ahd, &s); - while (AHD_DV_SIMQ_FROZEN(ahd) == 0) { - ahd->platform_data->flags |= AHD_DV_WAIT_SIMQ_RELEASE; - ahd_unlock(ahd, &s); - down_interruptible(&ahd->platform_data->dv_sem); - ahd_lock(ahd, &s); - } - ahd_unlock(ahd, &s); - - ahd_linux_dv_transition(ahd, cmd, &devinfo, targ); - } - -out: - if ((targ->flags & AHD_INQ_VALID) != 0 - && ahd_linux_get_device(ahd, devinfo.channel - 'A', - devinfo.target, devinfo.lun, - /*alloc*/FALSE) == NULL) { - /* - * The DV state machine failed to configure this device. - * This is normal if DV is disabled. Since we have inquiry - * data, filter it and use the "optimistic" negotiation - * parameters found in the inquiry string. - */ - ahd_linux_filter_inquiry(ahd, &devinfo); - if ((targ->flags & (AHD_BASIC_DV|AHD_ENHANCED_DV)) != 0) { - ahd_print_devinfo(ahd, &devinfo); - printf("DV failed to configure device. " - "Please file a bug report against " - "this driver.\n"); - } - } - - if (cmd != NULL) - free(cmd, M_DEVBUF); - - if (ahd->platform_data->dv_scsi_dev != NULL) { - free(ahd->platform_data->dv_scsi_dev, M_DEVBUF); - ahd->platform_data->dv_scsi_dev = NULL; - } - - ahd_lock(ahd, &s); - if (targ->dv_buffer != NULL) { - free(targ->dv_buffer, M_DEVBUF); - targ->dv_buffer = NULL; - } - if (targ->dv_buffer1 != NULL) { - free(targ->dv_buffer1, M_DEVBUF); - targ->dv_buffer1 = NULL; - } - targ->flags &= ~AHD_DV_REQUIRED; - if (targ->refcount == 0) - ahd_linux_free_target(ahd, targ); - ahd_unlock(ahd, &s); -} - -static __inline int -ahd_linux_dv_fallback(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) -{ - u_long s; - int retval; - - ahd_lock(ahd, &s); - retval = ahd_linux_fallback(ahd, devinfo); - ahd_unlock(ahd, &s); - - return (retval); -} - -static void -ahd_linux_dv_transition(struct ahd_softc *ahd, struct scsi_cmnd *cmd, - struct ahd_devinfo *devinfo, - struct ahd_linux_target *targ) -{ - u_int32_t status; - - status = aic_error_action(cmd, targ->inq_data, - ahd_cmd_get_transaction_status(cmd), - ahd_cmd_get_scsi_status(cmd)); - - -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - ahd_print_devinfo(ahd, devinfo); - printf("Entering ahd_linux_dv_transition, state= %d, " - "status= 0x%x, cmd->result= 0x%x\n", targ->dv_state, - status, cmd->result); - } -#endif - - switch (targ->dv_state) { - case AHD_DV_STATE_INQ_SHORT_ASYNC: - case AHD_DV_STATE_INQ_ASYNC: - switch (status & SS_MASK) { - case SS_NOP: - { - AHD_SET_DV_STATE(ahd, targ, targ->dv_state+1); - break; - } - case SS_INQ_REFRESH: - AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_INQ_SHORT_ASYNC); - break; - case SS_TUR: - case SS_RETRY: - AHD_SET_DV_STATE(ahd, targ, targ->dv_state); - if (ahd_cmd_get_transaction_status(cmd) - == CAM_REQUEUE_REQ) - targ->dv_state_retry--; - if ((status & SS_ERRMASK) == EBUSY) - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_BUSY); - if (targ->dv_state_retry < 10) - break; - /* FALLTHROUGH */ - default: - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - ahd_print_devinfo(ahd, devinfo); - printf("Failed DV inquiry, skipping\n"); - } -#endif - break; - } - break; - case AHD_DV_STATE_INQ_ASYNC_VERIFY: - switch (status & SS_MASK) { - case SS_NOP: - { - u_int xportflags; - u_int spi3data; - - if (memcmp(targ->inq_data, targ->dv_buffer, - AHD_LINUX_DV_INQ_LEN) != 0) { - /* - * Inquiry data must have changed. - * Try from the top again. - */ - AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_INQ_SHORT_ASYNC); - break; - } - - AHD_SET_DV_STATE(ahd, targ, targ->dv_state+1); - targ->flags |= AHD_INQ_VALID; - if (ahd_linux_user_dv_setting(ahd) == 0) - break; - - xportflags = targ->inq_data->flags; - if ((xportflags & (SID_Sync|SID_WBus16)) == 0) - break; - - spi3data = targ->inq_data->spi3data; - switch (spi3data & SID_SPI_CLOCK_DT_ST) { - default: - case SID_SPI_CLOCK_ST: - /* Assume only basic DV is supported. */ - targ->flags |= AHD_BASIC_DV; - break; - case SID_SPI_CLOCK_DT: - case SID_SPI_CLOCK_DT_ST: - targ->flags |= AHD_ENHANCED_DV; - break; - } - break; - } - case SS_INQ_REFRESH: - AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_INQ_SHORT_ASYNC); - break; - case SS_TUR: - case SS_RETRY: - AHD_SET_DV_STATE(ahd, targ, targ->dv_state); - if (ahd_cmd_get_transaction_status(cmd) - == CAM_REQUEUE_REQ) - targ->dv_state_retry--; - - if ((status & SS_ERRMASK) == EBUSY) - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_BUSY); - if (targ->dv_state_retry < 10) - break; - /* FALLTHROUGH */ - default: - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - ahd_print_devinfo(ahd, devinfo); - printf("Failed DV inquiry, skipping\n"); - } -#endif - break; - } - break; - case AHD_DV_STATE_INQ_VERIFY: - switch (status & SS_MASK) { - case SS_NOP: - { - - if (memcmp(targ->inq_data, targ->dv_buffer, - AHD_LINUX_DV_INQ_LEN) == 0) { - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); - break; - } - -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - int i; - - ahd_print_devinfo(ahd, devinfo); - printf("Inquiry buffer mismatch:"); - for (i = 0; i < AHD_LINUX_DV_INQ_LEN; i++) { - if ((i & 0xF) == 0) - printf("\n "); - printf("0x%x:0x0%x ", - ((uint8_t *)targ->inq_data)[i], - targ->dv_buffer[i]); - } - printf("\n"); - } -#endif - - if (ahd_linux_dv_fallback(ahd, devinfo) != 0) { - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); - break; - } - /* - * Do not count "falling back" - * against our retries. - */ - targ->dv_state_retry = 0; - AHD_SET_DV_STATE(ahd, targ, targ->dv_state); - break; - } - case SS_INQ_REFRESH: - AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_INQ_SHORT_ASYNC); - break; - case SS_TUR: - case SS_RETRY: - AHD_SET_DV_STATE(ahd, targ, targ->dv_state); - if (ahd_cmd_get_transaction_status(cmd) - == CAM_REQUEUE_REQ) { - targ->dv_state_retry--; - } else if ((status & SSQ_FALLBACK) != 0) { - if (ahd_linux_dv_fallback(ahd, devinfo) != 0) { - AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_EXIT); - break; - } - /* - * Do not count "falling back" - * against our retries. - */ - targ->dv_state_retry = 0; - } else if ((status & SS_ERRMASK) == EBUSY) - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_BUSY); - if (targ->dv_state_retry < 10) - break; - /* FALLTHROUGH */ - default: - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - ahd_print_devinfo(ahd, devinfo); - printf("Failed DV inquiry, skipping\n"); - } -#endif - break; - } - break; - - case AHD_DV_STATE_TUR: - switch (status & SS_MASK) { - case SS_NOP: - if ((targ->flags & AHD_BASIC_DV) != 0) { - ahd_linux_filter_inquiry(ahd, devinfo); - AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_INQ_VERIFY); - } else if ((targ->flags & AHD_ENHANCED_DV) != 0) { - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_REBD); - } else { - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); - } - break; - case SS_RETRY: - case SS_TUR: - if ((status & SS_ERRMASK) == EBUSY) { - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_BUSY); - break; - } - AHD_SET_DV_STATE(ahd, targ, targ->dv_state); - if (ahd_cmd_get_transaction_status(cmd) - == CAM_REQUEUE_REQ) { - targ->dv_state_retry--; - } else if ((status & SSQ_FALLBACK) != 0) { - if (ahd_linux_dv_fallback(ahd, devinfo) != 0) { - AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_EXIT); - break; - } - /* - * Do not count "falling back" - * against our retries. - */ - targ->dv_state_retry = 0; - } - if (targ->dv_state_retry >= 10) { -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - ahd_print_devinfo(ahd, devinfo); - printf("DV TUR reties exhausted\n"); - } -#endif - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); - break; - } - if (status & SSQ_DELAY) - ssleep(1); - - break; - case SS_START: - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_SU); - break; - case SS_INQ_REFRESH: - AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_INQ_SHORT_ASYNC); - break; - default: - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); - break; - } - break; - - case AHD_DV_STATE_REBD: - switch (status & SS_MASK) { - case SS_NOP: - { - uint32_t echo_size; - - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_WEB); - echo_size = scsi_3btoul(&targ->dv_buffer[1]); - echo_size &= 0x1FFF; -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - ahd_print_devinfo(ahd, devinfo); - printf("Echo buffer size= %d\n", echo_size); - } -#endif - if (echo_size == 0) { - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); - break; - } - - /* Generate the buffer pattern */ - targ->dv_echo_size = echo_size; - ahd_linux_generate_dv_pattern(targ); - /* - * Setup initial negotiation values. - */ - ahd_linux_filter_inquiry(ahd, devinfo); - break; - } - case SS_INQ_REFRESH: - AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_INQ_SHORT_ASYNC); - break; - case SS_RETRY: - AHD_SET_DV_STATE(ahd, targ, targ->dv_state); - if (ahd_cmd_get_transaction_status(cmd) - == CAM_REQUEUE_REQ) - targ->dv_state_retry--; - if (targ->dv_state_retry <= 10) - break; -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - ahd_print_devinfo(ahd, devinfo); - printf("DV REBD reties exhausted\n"); - } -#endif - /* FALLTHROUGH */ - case SS_FATAL: - default: - /* - * Setup initial negotiation values - * and try level 1 DV. - */ - ahd_linux_filter_inquiry(ahd, devinfo); - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_INQ_VERIFY); - targ->dv_echo_size = 0; - break; - } - break; - - case AHD_DV_STATE_WEB: - switch (status & SS_MASK) { - case SS_NOP: - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_REB); - break; - case SS_INQ_REFRESH: - AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_INQ_SHORT_ASYNC); - break; - case SS_RETRY: - AHD_SET_DV_STATE(ahd, targ, targ->dv_state); - if (ahd_cmd_get_transaction_status(cmd) - == CAM_REQUEUE_REQ) { - targ->dv_state_retry--; - } else if ((status & SSQ_FALLBACK) != 0) { - if (ahd_linux_dv_fallback(ahd, devinfo) != 0) { - AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_EXIT); - break; - } - /* - * Do not count "falling back" - * against our retries. - */ - targ->dv_state_retry = 0; - } - if (targ->dv_state_retry <= 10) - break; - /* FALLTHROUGH */ -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - ahd_print_devinfo(ahd, devinfo); - printf("DV WEB reties exhausted\n"); - } -#endif - default: - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); - break; - } - break; - - case AHD_DV_STATE_REB: - switch (status & SS_MASK) { - case SS_NOP: - if (memcmp(targ->dv_buffer, targ->dv_buffer1, - targ->dv_echo_size) != 0) { - if (ahd_linux_dv_fallback(ahd, devinfo) != 0) - AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_EXIT); - else - AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_WEB); - break; - } - - if (targ->dv_buffer != NULL) { - free(targ->dv_buffer, M_DEVBUF); - targ->dv_buffer = NULL; - } - if (targ->dv_buffer1 != NULL) { - free(targ->dv_buffer1, M_DEVBUF); - targ->dv_buffer1 = NULL; - } - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); - break; - case SS_INQ_REFRESH: - AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_INQ_SHORT_ASYNC); - break; - case SS_RETRY: - AHD_SET_DV_STATE(ahd, targ, targ->dv_state); - if (ahd_cmd_get_transaction_status(cmd) - == CAM_REQUEUE_REQ) { - targ->dv_state_retry--; - } else if ((status & SSQ_FALLBACK) != 0) { - if (ahd_linux_dv_fallback(ahd, devinfo) != 0) { - AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_EXIT); - break; - } - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_WEB); - } - if (targ->dv_state_retry <= 10) { - if ((status & (SSQ_DELAY_RANDOM|SSQ_DELAY))!= 0) - msleep(ahd->our_id*1000/10); - break; - } -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - ahd_print_devinfo(ahd, devinfo); - printf("DV REB reties exhausted\n"); - } -#endif - /* FALLTHROUGH */ - default: - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); - break; - } - break; - - case AHD_DV_STATE_SU: - switch (status & SS_MASK) { - case SS_NOP: - case SS_INQ_REFRESH: - AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_INQ_SHORT_ASYNC); - break; - default: - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); - break; - } - break; - - case AHD_DV_STATE_BUSY: - switch (status & SS_MASK) { - case SS_NOP: - case SS_INQ_REFRESH: - AHD_SET_DV_STATE(ahd, targ, - AHD_DV_STATE_INQ_SHORT_ASYNC); - break; - case SS_TUR: - case SS_RETRY: - AHD_SET_DV_STATE(ahd, targ, targ->dv_state); - if (ahd_cmd_get_transaction_status(cmd) - == CAM_REQUEUE_REQ) { - targ->dv_state_retry--; - } else if (targ->dv_state_retry < 60) { - if ((status & SSQ_DELAY) != 0) - ssleep(1); - } else { -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - ahd_print_devinfo(ahd, devinfo); - printf("DV BUSY reties exhausted\n"); - } -#endif - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); - } - break; - default: - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); - break; - } - break; - - default: - printf("%s: Invalid DV completion state %d\n", ahd_name(ahd), - targ->dv_state); - AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT); - break; - } -} - -static void -ahd_linux_dv_fill_cmd(struct ahd_softc *ahd, struct scsi_cmnd *cmd, - struct ahd_devinfo *devinfo) -{ - memset(cmd, 0, sizeof(struct scsi_cmnd)); - cmd->device = ahd->platform_data->dv_scsi_dev; - cmd->scsi_done = ahd_linux_dv_complete; -} - -/* - * Synthesize an inquiry command. On the return trip, it'll be - * sniffed and the device transfer settings set for us. - */ -static void -ahd_linux_dv_inq(struct ahd_softc *ahd, struct scsi_cmnd *cmd, - struct ahd_devinfo *devinfo, struct ahd_linux_target *targ, - u_int request_length) -{ - -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - ahd_print_devinfo(ahd, devinfo); - printf("Sending INQ\n"); - } -#endif - if (targ->inq_data == NULL) - targ->inq_data = malloc(AHD_LINUX_DV_INQ_LEN, - M_DEVBUF, M_WAITOK); - if (targ->dv_state > AHD_DV_STATE_INQ_ASYNC) { - if (targ->dv_buffer != NULL) - free(targ->dv_buffer, M_DEVBUF); - targ->dv_buffer = malloc(AHD_LINUX_DV_INQ_LEN, - M_DEVBUF, M_WAITOK); - } - - ahd_linux_dv_fill_cmd(ahd, cmd, devinfo); - cmd->sc_data_direction = DMA_FROM_DEVICE; - cmd->cmd_len = 6; - cmd->cmnd[0] = INQUIRY; - cmd->cmnd[4] = request_length; - cmd->request_bufflen = request_length; - if (targ->dv_state > AHD_DV_STATE_INQ_ASYNC) - cmd->request_buffer = targ->dv_buffer; - else - cmd->request_buffer = targ->inq_data; - memset(cmd->request_buffer, 0, AHD_LINUX_DV_INQ_LEN); -} - -static void -ahd_linux_dv_tur(struct ahd_softc *ahd, struct scsi_cmnd *cmd, - struct ahd_devinfo *devinfo) -{ - -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - ahd_print_devinfo(ahd, devinfo); - printf("Sending TUR\n"); - } -#endif - /* Do a TUR to clear out any non-fatal transitional state */ - ahd_linux_dv_fill_cmd(ahd, cmd, devinfo); - cmd->sc_data_direction = DMA_NONE; - cmd->cmd_len = 6; - cmd->cmnd[0] = TEST_UNIT_READY; -} - -#define AHD_REBD_LEN 4 - -static void -ahd_linux_dv_rebd(struct ahd_softc *ahd, struct scsi_cmnd *cmd, - struct ahd_devinfo *devinfo, struct ahd_linux_target *targ) -{ - -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - ahd_print_devinfo(ahd, devinfo); - printf("Sending REBD\n"); - } -#endif - if (targ->dv_buffer != NULL) - free(targ->dv_buffer, M_DEVBUF); - targ->dv_buffer = malloc(AHD_REBD_LEN, M_DEVBUF, M_WAITOK); - ahd_linux_dv_fill_cmd(ahd, cmd, devinfo); - cmd->sc_data_direction = DMA_FROM_DEVICE; - cmd->cmd_len = 10; - cmd->cmnd[0] = READ_BUFFER; - cmd->cmnd[1] = 0x0b; - scsi_ulto3b(AHD_REBD_LEN, &cmd->cmnd[6]); - cmd->request_bufflen = AHD_REBD_LEN; - cmd->underflow = cmd->request_bufflen; - cmd->request_buffer = targ->dv_buffer; -} - -static void -ahd_linux_dv_web(struct ahd_softc *ahd, struct scsi_cmnd *cmd, - struct ahd_devinfo *devinfo, struct ahd_linux_target *targ) -{ - -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - ahd_print_devinfo(ahd, devinfo); - printf("Sending WEB\n"); - } -#endif - ahd_linux_dv_fill_cmd(ahd, cmd, devinfo); - cmd->sc_data_direction = DMA_TO_DEVICE; - cmd->cmd_len = 10; - cmd->cmnd[0] = WRITE_BUFFER; - cmd->cmnd[1] = 0x0a; - scsi_ulto3b(targ->dv_echo_size, &cmd->cmnd[6]); - cmd->request_bufflen = targ->dv_echo_size; - cmd->underflow = cmd->request_bufflen; - cmd->request_buffer = targ->dv_buffer; -} - -static void -ahd_linux_dv_reb(struct ahd_softc *ahd, struct scsi_cmnd *cmd, - struct ahd_devinfo *devinfo, struct ahd_linux_target *targ) -{ - -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - ahd_print_devinfo(ahd, devinfo); - printf("Sending REB\n"); - } -#endif - ahd_linux_dv_fill_cmd(ahd, cmd, devinfo); - cmd->sc_data_direction = DMA_FROM_DEVICE; - cmd->cmd_len = 10; - cmd->cmnd[0] = READ_BUFFER; - cmd->cmnd[1] = 0x0a; - scsi_ulto3b(targ->dv_echo_size, &cmd->cmnd[6]); - cmd->request_bufflen = targ->dv_echo_size; - cmd->underflow = cmd->request_bufflen; - cmd->request_buffer = targ->dv_buffer1; -} - -static void -ahd_linux_dv_su(struct ahd_softc *ahd, struct scsi_cmnd *cmd, - struct ahd_devinfo *devinfo, - struct ahd_linux_target *targ) -{ - u_int le; - - le = SID_IS_REMOVABLE(targ->inq_data) ? SSS_LOEJ : 0; - -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - ahd_print_devinfo(ahd, devinfo); - printf("Sending SU\n"); - } -#endif - ahd_linux_dv_fill_cmd(ahd, cmd, devinfo); - cmd->sc_data_direction = DMA_NONE; - cmd->cmd_len = 6; - cmd->cmnd[0] = START_STOP_UNIT; - cmd->cmnd[4] = le | SSS_START; -} - -static int -ahd_linux_fallback(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) -{ - struct ahd_linux_target *targ; - struct ahd_initiator_tinfo *tinfo; - struct ahd_transinfo *goal; - struct ahd_tmode_tstate *tstate; - u_int width; - u_int period; - u_int offset; - u_int ppr_options; - u_int cur_speed; - u_int wide_speed; - u_int narrow_speed; - u_int fallback_speed; - -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - ahd_print_devinfo(ahd, devinfo); - printf("Trying to fallback\n"); - } -#endif - targ = ahd->platform_data->targets[devinfo->target_offset]; - tinfo = ahd_fetch_transinfo(ahd, devinfo->channel, - devinfo->our_scsiid, - devinfo->target, &tstate); - goal = &tinfo->goal; - width = goal->width; - period = goal->period; - offset = goal->offset; - ppr_options = goal->ppr_options; - if (offset == 0) - period = AHD_ASYNC_XFER_PERIOD; - if (targ->dv_next_narrow_period == 0) - targ->dv_next_narrow_period = MAX(period, AHD_SYNCRATE_ULTRA2); - if (targ->dv_next_wide_period == 0) - targ->dv_next_wide_period = period; - if (targ->dv_max_width == 0) - targ->dv_max_width = width; - if (targ->dv_max_ppr_options == 0) - targ->dv_max_ppr_options = ppr_options; - if (targ->dv_last_ppr_options == 0) - targ->dv_last_ppr_options = ppr_options; - - cur_speed = aic_calc_speed(width, period, offset, AHD_SYNCRATE_MIN); - wide_speed = aic_calc_speed(MSG_EXT_WDTR_BUS_16_BIT, - targ->dv_next_wide_period, - MAX_OFFSET, AHD_SYNCRATE_MIN); - narrow_speed = aic_calc_speed(MSG_EXT_WDTR_BUS_8_BIT, - targ->dv_next_narrow_period, - MAX_OFFSET, AHD_SYNCRATE_MIN); - fallback_speed = aic_calc_speed(width, period+1, offset, - AHD_SYNCRATE_MIN); -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - printf("cur_speed= %d, wide_speed= %d, narrow_speed= %d, " - "fallback_speed= %d\n", cur_speed, wide_speed, - narrow_speed, fallback_speed); - } -#endif - - if (cur_speed > 160000) { - /* - * Paced/DT/IU_REQ only transfer speeds. All we - * can do is fallback in terms of syncrate. - */ - period++; - } else if (cur_speed > 80000) { - if ((ppr_options & MSG_EXT_PPR_IU_REQ) != 0) { - /* - * Try without IU_REQ as it may be confusing - * an expander. - */ - ppr_options &= ~MSG_EXT_PPR_IU_REQ; - } else { - /* - * Paced/DT only transfer speeds. All we - * can do is fallback in terms of syncrate. - */ - period++; - ppr_options = targ->dv_max_ppr_options; - } - } else if (cur_speed > 3300) { - - /* - * In this range we the following - * options ordered from highest to - * lowest desireability: - * - * o Wide/DT - * o Wide/non-DT - * o Narrow at a potentally higher sync rate. - * - * All modes are tested with and without IU_REQ - * set since using IUs may confuse an expander. - */ - if ((ppr_options & MSG_EXT_PPR_IU_REQ) != 0) { - - ppr_options &= ~MSG_EXT_PPR_IU_REQ; - } else if ((ppr_options & MSG_EXT_PPR_DT_REQ) != 0) { - /* - * Try going non-DT. - */ - ppr_options = targ->dv_max_ppr_options; - ppr_options &= ~MSG_EXT_PPR_DT_REQ; - } else if (targ->dv_last_ppr_options != 0) { - /* - * Try without QAS or any other PPR options. - * We may need a non-PPR message to work with - * an expander. We look at the "last PPR options" - * so we will perform this fallback even if the - * target responded to our PPR negotiation with - * no option bits set. - */ - ppr_options = 0; - } else if (width == MSG_EXT_WDTR_BUS_16_BIT) { - /* - * If the next narrow speed is greater than - * the next wide speed, fallback to narrow. - * Otherwise fallback to the next DT/Wide setting. - * The narrow async speed will always be smaller - * than the wide async speed, so handle this case - * specifically. - */ - ppr_options = targ->dv_max_ppr_options; - if (narrow_speed > fallback_speed - || period >= AHD_ASYNC_XFER_PERIOD) { - targ->dv_next_wide_period = period+1; - width = MSG_EXT_WDTR_BUS_8_BIT; - period = targ->dv_next_narrow_period; - } else { - period++; - } - } else if ((ahd->features & AHD_WIDE) != 0 - && targ->dv_max_width != 0 - && wide_speed >= fallback_speed - && (targ->dv_next_wide_period <= AHD_ASYNC_XFER_PERIOD - || period >= AHD_ASYNC_XFER_PERIOD)) { - - /* - * We are narrow. Try falling back - * to the next wide speed with - * all supported ppr options set. - */ - targ->dv_next_narrow_period = period+1; - width = MSG_EXT_WDTR_BUS_16_BIT; - period = targ->dv_next_wide_period; - ppr_options = targ->dv_max_ppr_options; - } else { - /* Only narrow fallback is allowed. */ - period++; - ppr_options = targ->dv_max_ppr_options; - } - } else { - return (-1); - } - offset = MAX_OFFSET; - ahd_find_syncrate(ahd, &period, &ppr_options, AHD_SYNCRATE_PACED); - ahd_set_width(ahd, devinfo, width, AHD_TRANS_GOAL, FALSE); - if (period == 0) { - period = 0; - offset = 0; - ppr_options = 0; - if (width == MSG_EXT_WDTR_BUS_8_BIT) - targ->dv_next_narrow_period = AHD_ASYNC_XFER_PERIOD; - else - targ->dv_next_wide_period = AHD_ASYNC_XFER_PERIOD; - } - ahd_set_syncrate(ahd, devinfo, period, offset, - ppr_options, AHD_TRANS_GOAL, FALSE); - targ->dv_last_ppr_options = ppr_options; - return (0); -} - -static void -ahd_linux_dv_timeout(struct scsi_cmnd *cmd) -{ - struct ahd_softc *ahd; - struct scb *scb; - u_long flags; - - ahd = *((struct ahd_softc **)cmd->device->host->hostdata); - ahd_lock(ahd, &flags); - -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) { - printf("%s: Timeout while doing DV command %x.\n", - ahd_name(ahd), cmd->cmnd[0]); - ahd_dump_card_state(ahd); - } -#endif - - /* - * Guard against "done race". No action is - * required if we just completed. - */ - if ((scb = (struct scb *)cmd->host_scribble) == NULL) { - ahd_unlock(ahd, &flags); - return; - } - - /* - * Command has not completed. Mark this - * SCB as having failing status prior to - * resetting the bus, so we get the correct - * error code. - */ - if ((scb->flags & SCB_SENSE) != 0) - ahd_set_transaction_status(scb, CAM_AUTOSENSE_FAIL); - else - ahd_set_transaction_status(scb, CAM_CMD_TIMEOUT); - ahd_reset_channel(ahd, cmd->device->channel + 'A', /*initiate*/TRUE); - - /* - * Add a minimal bus settle delay for devices that are slow to - * respond after bus resets. - */ - ahd_freeze_simq(ahd); - init_timer(&ahd->platform_data->reset_timer); - ahd->platform_data->reset_timer.data = (u_long)ahd; - ahd->platform_data->reset_timer.expires = jiffies + HZ / 2; - ahd->platform_data->reset_timer.function = - (ahd_linux_callback_t *)ahd_release_simq; - add_timer(&ahd->platform_data->reset_timer); - ahd_linux_run_complete_queue(ahd); - ahd_unlock(ahd, &flags); -} - -static void -ahd_linux_dv_complete(struct scsi_cmnd *cmd) -{ - struct ahd_softc *ahd; - - ahd = *((struct ahd_softc **)cmd->device->host->hostdata); - - /* Delete the DV timer before it goes off! */ - scsi_delete_timer(cmd); - -#ifdef AHD_DEBUG - if (ahd_debug & AHD_SHOW_DV) - printf("%s:%c:%d: Command completed, status= 0x%x\n", - ahd_name(ahd), cmd->device->channel, cmd->device->id, - cmd->result); -#endif - - /* Wake up the state machine */ - up(&ahd->platform_data->dv_cmd_sem); -} - -static void -ahd_linux_generate_dv_pattern(struct ahd_linux_target *targ) -{ - uint16_t b; - u_int i; - u_int j; - - if (targ->dv_buffer != NULL) - free(targ->dv_buffer, M_DEVBUF); - targ->dv_buffer = malloc(targ->dv_echo_size, M_DEVBUF, M_WAITOK); - if (targ->dv_buffer1 != NULL) - free(targ->dv_buffer1, M_DEVBUF); - targ->dv_buffer1 = malloc(targ->dv_echo_size, M_DEVBUF, M_WAITOK); - - i = 0; - - b = 0x0001; - for (j = 0 ; i < targ->dv_echo_size; j++) { - if (j < 32) { - /* - * 32bytes of sequential numbers. - */ - targ->dv_buffer[i++] = j & 0xff; - } else if (j < 48) { - /* - * 32bytes of repeating 0x0000, 0xffff. - */ - targ->dv_buffer[i++] = (j & 0x02) ? 0xff : 0x00; - } else if (j < 64) { - /* - * 32bytes of repeating 0x5555, 0xaaaa. - */ - targ->dv_buffer[i++] = (j & 0x02) ? 0xaa : 0x55; - } else { - /* - * Remaining buffer is filled with a repeating - * patter of: - * - * 0xffff - * ~0x0001 << shifted once in each loop. - */ - if (j & 0x02) { - if (j & 0x01) { - targ->dv_buffer[i++] = ~(b >> 8) & 0xff; - b <<= 1; - if (b == 0x0000) - b = 0x0001; - } else { - targ->dv_buffer[i++] = (~b & 0xff); - } - } else { - targ->dv_buffer[i++] = 0xff; - } - } - } -} - static u_int ahd_linux_user_tagdepth(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) { @@ -3359,100 +1399,23 @@ ahd_linux_user_tagdepth(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) return (tags); } -static u_int -ahd_linux_user_dv_setting(struct ahd_softc *ahd) -{ - static int warned_user; - int dv; - - if (ahd->unit >= NUM_ELEMENTS(aic79xx_dv_settings)) { - - if (warned_user == 0) { - printf(KERN_WARNING -"aic79xx: WARNING: Insufficient dv settings instances\n" -"aic79xx: for installed controllers. Using defaults\n" -"aic79xx: Please update the aic79xx_dv_settings array in" -"aic79xx: the aic79xx_osm.c source file.\n"); - warned_user++; - } - dv = -1; - } else { - - dv = aic79xx_dv_settings[ahd->unit]; - } - - if (dv < 0) { - /* - * Apply the default. - */ - dv = 1; - if (ahd->seep_config != 0) - dv = (ahd->seep_config->bios_control & CFENABLEDV); - } - return (dv); -} - -static void -ahd_linux_setup_user_rd_strm_settings(struct ahd_softc *ahd) -{ - static int warned_user; - u_int rd_strm_mask; - u_int target_id; - - /* - * If we have specific read streaming info for this controller, - * apply it. Otherwise use the defaults. - */ - if (ahd->unit >= NUM_ELEMENTS(aic79xx_rd_strm_info)) { - - if (warned_user == 0) { - - printf(KERN_WARNING -"aic79xx: WARNING: Insufficient rd_strm instances\n" -"aic79xx: for installed controllers. Using defaults\n" -"aic79xx: Please update the aic79xx_rd_strm_info array\n" -"aic79xx: in the aic79xx_osm.c source file.\n"); - warned_user++; - } - rd_strm_mask = AIC79XX_CONFIGED_RD_STRM; - } else { - - rd_strm_mask = aic79xx_rd_strm_info[ahd->unit]; - } - for (target_id = 0; target_id < 16; target_id++) { - struct ahd_devinfo devinfo; - struct ahd_initiator_tinfo *tinfo; - struct ahd_tmode_tstate *tstate; - - tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id, - target_id, &tstate); - ahd_compile_devinfo(&devinfo, ahd->our_id, target_id, - CAM_LUN_WILDCARD, 'A', ROLE_INITIATOR); - tinfo->user.ppr_options &= ~MSG_EXT_PPR_RD_STRM; - if ((rd_strm_mask & devinfo.target_mask) != 0) - tinfo->user.ppr_options |= MSG_EXT_PPR_RD_STRM; - } -} - /* * Determines the queue depth for a given device. */ static void -ahd_linux_device_queue_depth(struct ahd_softc *ahd, - struct ahd_linux_device *dev) +ahd_linux_device_queue_depth(struct scsi_device *sdev) { struct ahd_devinfo devinfo; u_int tags; + struct ahd_softc *ahd = *((struct ahd_softc **)sdev->host->hostdata); ahd_compile_devinfo(&devinfo, ahd->our_id, - dev->target->target, dev->lun, - dev->target->channel == 0 ? 'A' : 'B', + sdev->sdev_target->id, sdev->lun, + sdev->sdev_target->channel == 0 ? 'A' : 'B', ROLE_INITIATOR); tags = ahd_linux_user_tagdepth(ahd, &devinfo); - if (tags != 0 - && dev->scsi_device != NULL - && dev->scsi_device->tagged_supported != 0) { + if (tags != 0 && sdev->tagged_supported != 0) { ahd_set_tags(ahd, &devinfo, AHD_QUEUE_TAGGED); ahd_print_devinfo(ahd, &devinfo); @@ -3507,9 +1470,6 @@ ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev, if ((ahd->user_discenable & mask) != 0) hscb->control |= DISCENB; - if (AHD_DV_CMD(cmd) != 0) - scb->flags |= SCB_SILENT; - if ((tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0) scb->flags |= SCB_PACKETIZED; @@ -3540,9 +1500,10 @@ ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev, hscb->cdb_len = cmd->cmd_len; memcpy(hscb->shared_data.idata.cdb, cmd->cmnd, hscb->cdb_len); - scb->sg_count = 0; + scb->platform_data->xfer_len = 0; ahd_set_residual(scb, 0); ahd_set_sense_residual(scb, 0); + scb->sg_count = 0; if (cmd->use_sg != 0) { void *sg; struct scatterlist *cur_seg; @@ -3585,14 +1546,6 @@ ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev, dev->active++; dev->commands_issued++; - /* Update the error counting bucket and dump if needed */ - if (dev->target->cmds_since_error) { - dev->target->cmds_since_error++; - if (dev->target->cmds_since_error > - AHD_LINUX_ERR_THRESH) - dev->target->cmds_since_error = 0; - } - if ((dev->flags & AHD_DEV_PERIODIC_OTAG) != 0) dev->commands_since_idle_or_otag++; scb->flags |= SCB_ACTIVE; @@ -3614,7 +1567,6 @@ ahd_linux_isr(int irq, void *dev_id, struct pt_regs * regs) ahd = (struct ahd_softc *) dev_id; ahd_lock(ahd, &flags); ours = ahd_intr(ahd); - ahd_linux_run_complete_queue(ahd); ahd_unlock(ahd, &flags); return IRQ_RETVAL(ours); } @@ -3623,110 +1575,6 @@ void ahd_platform_flushwork(struct ahd_softc *ahd) { - while (ahd_linux_run_complete_queue(ahd) != NULL) - ; -} - -static struct ahd_linux_target* -ahd_linux_alloc_target(struct ahd_softc *ahd, u_int channel, u_int target) -{ - struct ahd_linux_target *targ; - - targ = malloc(sizeof(*targ), M_DEVBUF, M_NOWAIT); - if (targ == NULL) - return (NULL); - memset(targ, 0, sizeof(*targ)); - targ->channel = channel; - targ->target = target; - targ->ahd = ahd; - targ->flags = AHD_DV_REQUIRED; - ahd->platform_data->targets[target] = targ; - return (targ); -} - -static void -ahd_linux_free_target(struct ahd_softc *ahd, struct ahd_linux_target *targ) -{ - struct ahd_devinfo devinfo; - struct ahd_initiator_tinfo *tinfo; - struct ahd_tmode_tstate *tstate; - u_int our_id; - u_int target_offset; - char channel; - - /* - * Force a negotiation to async/narrow on any - * future command to this device unless a bus - * reset occurs between now and that command. - */ - channel = 'A' + targ->channel; - our_id = ahd->our_id; - target_offset = targ->target; - tinfo = ahd_fetch_transinfo(ahd, channel, our_id, - targ->target, &tstate); - ahd_compile_devinfo(&devinfo, our_id, targ->target, CAM_LUN_WILDCARD, - channel, ROLE_INITIATOR); - ahd_set_syncrate(ahd, &devinfo, 0, 0, 0, - AHD_TRANS_GOAL, /*paused*/FALSE); - ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT, - AHD_TRANS_GOAL, /*paused*/FALSE); - ahd_update_neg_request(ahd, &devinfo, tstate, tinfo, AHD_NEG_ALWAYS); - ahd->platform_data->targets[target_offset] = NULL; - if (targ->inq_data != NULL) - free(targ->inq_data, M_DEVBUF); - if (targ->dv_buffer != NULL) - free(targ->dv_buffer, M_DEVBUF); - if (targ->dv_buffer1 != NULL) - free(targ->dv_buffer1, M_DEVBUF); - free(targ, M_DEVBUF); -} - -static struct ahd_linux_device* -ahd_linux_alloc_device(struct ahd_softc *ahd, - struct ahd_linux_target *targ, u_int lun) -{ - struct ahd_linux_device *dev; - - dev = malloc(sizeof(*dev), M_DEVBUG, M_NOWAIT); - if (dev == NULL) - return (NULL); - memset(dev, 0, sizeof(*dev)); - init_timer(&dev->timer); - dev->flags = AHD_DEV_UNCONFIGURED; - dev->lun = lun; - dev->target = targ; - - /* - * We start out life using untagged - * transactions of which we allow one. - */ - dev->openings = 1; - - /* - * Set maxtags to 0. This will be changed if we - * later determine that we are dealing with - * a tagged queuing capable device. - */ - dev->maxtags = 0; - - targ->refcount++; - targ->devices[lun] = dev; - return (dev); -} - -static void -ahd_linux_free_device(struct ahd_softc *ahd, struct ahd_linux_device *dev) -{ - struct ahd_linux_target *targ; - - del_timer(&dev->timer); - targ = dev->target; - targ->devices[dev->lun] = NULL; - free(dev, M_DEVBUF); - targ->refcount--; - if (targ->refcount == 0 - && (targ->flags & AHD_DV_REQUIRED) == 0) - ahd_linux_free_target(ahd, targ); } void @@ -3737,10 +1585,14 @@ ahd_send_async(struct ahd_softc *ahd, char channel, case AC_TRANSFER_NEG: { char buf[80]; + struct scsi_target *starget; struct ahd_linux_target *targ; struct info_str info; struct ahd_initiator_tinfo *tinfo; struct ahd_tmode_tstate *tstate; + unsigned int target_ppr_options; + + BUG_ON(target == CAM_TARGET_WILDCARD); info.buffer = buf; info.length = sizeof(buf); @@ -3764,32 +1616,30 @@ ahd_send_async(struct ahd_softc *ahd, char channel, * Don't bother reporting results that * are identical to those last reported. */ - targ = ahd->platform_data->targets[target]; + starget = ahd->platform_data->starget[target]; + targ = scsi_transport_target_data(starget); if (targ == NULL) break; - if (tinfo->curr.period == targ->last_tinfo.period - && tinfo->curr.width == targ->last_tinfo.width - && tinfo->curr.offset == targ->last_tinfo.offset - && tinfo->curr.ppr_options == targ->last_tinfo.ppr_options) + + target_ppr_options = + (spi_dt(starget) ? MSG_EXT_PPR_DT_REQ : 0) + + (spi_qas(starget) ? MSG_EXT_PPR_QAS_REQ : 0) + + (spi_iu(starget) ? MSG_EXT_PPR_IU_REQ : 0); + + if (tinfo->curr.period == spi_period(starget) + && tinfo->curr.width == spi_width(starget) + && tinfo->curr.offset == spi_offset(starget) + && tinfo->curr.ppr_options == target_ppr_options) if (bootverbose == 0) break; - targ->last_tinfo.period = tinfo->curr.period; - targ->last_tinfo.width = tinfo->curr.width; - targ->last_tinfo.offset = tinfo->curr.offset; - targ->last_tinfo.ppr_options = tinfo->curr.ppr_options; - - printf("(%s:%c:", ahd_name(ahd), channel); - if (target == CAM_TARGET_WILDCARD) - printf("*): "); - else - printf("%d): ", target); - ahd_format_transinfo(&info, &tinfo->curr); - if (info.pos < info.length) - *info.buffer = '\0'; - else - buf[info.length - 1] = '\0'; - printf("%s", buf); + spi_period(starget) = tinfo->curr.period; + spi_width(starget) = tinfo->curr.width; + spi_offset(starget) = tinfo->curr.offset; + spi_dt(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_DT_REQ; + spi_qas(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_QAS_REQ; + spi_iu(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ; + spi_display_xfer_agreement(starget); break; } case AC_SENT_BDR: @@ -3816,7 +1666,7 @@ ahd_send_async(struct ahd_softc *ahd, char channel, void ahd_done(struct ahd_softc *ahd, struct scb *scb) { - Scsi_Cmnd *cmd; + struct scsi_cmnd *cmd; struct ahd_linux_device *dev; if ((scb->flags & SCB_ACTIVE) == 0) { @@ -3884,19 +1734,8 @@ ahd_done(struct ahd_softc *ahd, struct scb *scb) ahd_set_transaction_status(scb, CAM_REQ_CMP); } } else if (ahd_get_transaction_status(scb) == CAM_SCSI_STATUS_ERROR) { - ahd_linux_handle_scsi_status(ahd, dev, scb); - } else if (ahd_get_transaction_status(scb) == CAM_SEL_TIMEOUT) { - dev->flags |= AHD_DEV_UNCONFIGURED; - if (AHD_DV_CMD(cmd) == FALSE) - dev->target->flags &= ~AHD_DV_REQUIRED; + ahd_linux_handle_scsi_status(ahd, cmd->device, scb); } - /* - * Start DV for devices that require it assuming the first command - * sent does not result in a selection timeout. - */ - if (ahd_get_transaction_status(scb) != CAM_SEL_TIMEOUT - && (dev->target->flags & AHD_DV_REQUIRED) != 0) - ahd_linux_start_dv(ahd); if (dev->openings == 1 && ahd_get_transaction_status(scb) == CAM_REQ_CMP @@ -3917,42 +1756,32 @@ ahd_done(struct ahd_softc *ahd, struct scb *scb) if (dev->active == 0) dev->commands_since_idle_or_otag = 0; - if ((dev->flags & AHD_DEV_UNCONFIGURED) != 0 - && dev->active == 0 - && (dev->flags & AHD_DEV_TIMER_ACTIVE) == 0) - ahd_linux_free_device(ahd, dev); - if ((scb->flags & SCB_RECOVERY_SCB) != 0) { printf("Recovery SCB completes\n"); if (ahd_get_transaction_status(scb) == CAM_BDR_SENT || ahd_get_transaction_status(scb) == CAM_REQ_ABORTED) ahd_set_transaction_status(scb, CAM_CMD_TIMEOUT); - if ((scb->platform_data->flags & AHD_SCB_UP_EH_SEM) != 0) { - scb->platform_data->flags &= ~AHD_SCB_UP_EH_SEM; + if ((ahd->platform_data->flags & AHD_SCB_UP_EH_SEM) != 0) { + ahd->platform_data->flags &= ~AHD_SCB_UP_EH_SEM; up(&ahd->platform_data->eh_sem); } } ahd_free_scb(ahd, scb); ahd_linux_queue_cmd_complete(ahd, cmd); - - if ((ahd->platform_data->flags & AHD_DV_WAIT_SIMQ_EMPTY) != 0 - && LIST_FIRST(&ahd->pending_scbs) == NULL) { - ahd->platform_data->flags &= ~AHD_DV_WAIT_SIMQ_EMPTY; - up(&ahd->platform_data->dv_sem); - } } static void ahd_linux_handle_scsi_status(struct ahd_softc *ahd, - struct ahd_linux_device *dev, struct scb *scb) + struct scsi_device *sdev, struct scb *scb) { struct ahd_devinfo devinfo; + struct ahd_linux_device *dev = scsi_transport_device_data(sdev); ahd_compile_devinfo(&devinfo, ahd->our_id, - dev->target->target, dev->lun, - dev->target->channel == 0 ? 'A' : 'B', + sdev->sdev_target->id, sdev->lun, + sdev->sdev_target->channel == 0 ? 'A' : 'B', ROLE_INITIATOR); /* @@ -3971,7 +1800,7 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd, case SCSI_STATUS_CHECK_COND: case SCSI_STATUS_CMD_TERMINATED: { - Scsi_Cmnd *cmd; + struct scsi_cmnd *cmd; /* * Copy sense information to the OS's cmd @@ -4024,7 +1853,6 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd, break; } case SCSI_STATUS_QUEUE_FULL: - { /* * By the time the core driver has returned this * command, all other commands that were queued @@ -4085,98 +1913,23 @@ ahd_linux_handle_scsi_status(struct ahd_softc *ahd, (dev->flags & AHD_DEV_Q_BASIC) ? AHD_QUEUE_BASIC : AHD_QUEUE_TAGGED); ahd_set_scsi_status(scb, SCSI_STATUS_BUSY); - /* FALLTHROUGH */ - } - case SCSI_STATUS_BUSY: - /* - * Set a short timer to defer sending commands for - * a bit since Linux will not delay in this case. - */ - if ((dev->flags & AHD_DEV_TIMER_ACTIVE) != 0) { - printf("%s:%c:%d: Device Timer still active during " - "busy processing\n", ahd_name(ahd), - dev->target->channel, dev->target->target); - break; - } - dev->flags |= AHD_DEV_TIMER_ACTIVE; - dev->qfrozen++; - init_timer(&dev->timer); - dev->timer.data = (u_long)dev; - dev->timer.expires = jiffies + (HZ/2); - dev->timer.function = ahd_linux_dev_timed_unfreeze; - add_timer(&dev->timer); - break; } } static void -ahd_linux_queue_cmd_complete(struct ahd_softc *ahd, Scsi_Cmnd *cmd) +ahd_linux_queue_cmd_complete(struct ahd_softc *ahd, struct scsi_cmnd *cmd) { - /* - * Typically, the complete queue has very few entries - * queued to it before the queue is emptied by - * ahd_linux_run_complete_queue, so sorting the entries - * by generation number should be inexpensive. - * We perform the sort so that commands that complete - * with an error are retuned in the order origionally - * queued to the controller so that any subsequent retries - * are performed in order. The underlying ahd routines do - * not guarantee the order that aborted commands will be - * returned to us. - */ - struct ahd_completeq *completeq; - struct ahd_cmd *list_cmd; - struct ahd_cmd *acmd; - /* * Map CAM error codes into Linux Error codes. We * avoid the conversion so that the DV code has the * full error information available when making * state change decisions. */ - if (AHD_DV_CMD(cmd) == FALSE) { + { uint32_t status; u_int new_status; status = ahd_cmd_get_transaction_status(cmd); - if (status != CAM_REQ_CMP) { - struct ahd_linux_device *dev; - struct ahd_devinfo devinfo; - cam_status cam_status; - uint32_t action; - u_int scsi_status; - - dev = ahd_linux_get_device(ahd, cmd->device->channel, - cmd->device->id, - cmd->device->lun, - /*alloc*/FALSE); - - if (dev == NULL) - goto no_fallback; - - ahd_compile_devinfo(&devinfo, - ahd->our_id, - dev->target->target, dev->lun, - dev->target->channel == 0 ? 'A':'B', - ROLE_INITIATOR); - - scsi_status = ahd_cmd_get_scsi_status(cmd); - cam_status = ahd_cmd_get_transaction_status(cmd); - action = aic_error_action(cmd, dev->target->inq_data, - cam_status, scsi_status); - if ((action & SSQ_FALLBACK) != 0) { - - /* Update stats */ - dev->target->errors_detected++; - if (dev->target->cmds_since_error == 0) - dev->target->cmds_since_error++; - else { - dev->target->cmds_since_error = 0; - ahd_linux_fallback(ahd, &devinfo); - } - } - } -no_fallback: switch (status) { case CAM_REQ_INPROG: case CAM_REQ_CMP: @@ -4221,26 +1974,7 @@ ahd_linux_queue_cmd_complete(struct ahd_softc *ahd, Scsi_Cmnd *cmd) new_status = DID_ERROR; break; case CAM_REQUEUE_REQ: - /* - * If we want the request requeued, make sure there - * are sufficent retries. In the old scsi error code, - * we used to be able to specify a result code that - * bypassed the retry count. Now we must use this - * hack. We also "fake" a check condition with - * a sense code of ABORTED COMMAND. This seems to - * evoke a retry even if this command is being sent - * via the eh thread. Ick! Ick! Ick! - */ - if (cmd->retries > 0) - cmd->retries--; - new_status = DID_OK; - ahd_cmd_set_scsi_status(cmd, SCSI_STATUS_CHECK_COND); - cmd->result |= (DRIVER_SENSE << 24); - memset(cmd->sense_buffer, 0, - sizeof(cmd->sense_buffer)); - cmd->sense_buffer[0] = SSD_ERRCODE_VALID - | SSD_CURRENT_ERROR; - cmd->sense_buffer[2] = SSD_KEY_ABORTED_COMMAND; + new_status = DID_REQUEUE; break; default: /* We should never get here */ @@ -4251,116 +1985,23 @@ ahd_linux_queue_cmd_complete(struct ahd_softc *ahd, Scsi_Cmnd *cmd) ahd_cmd_set_transaction_status(cmd, new_status); } - completeq = &ahd->platform_data->completeq; - list_cmd = TAILQ_FIRST(completeq); - acmd = (struct ahd_cmd *)cmd; - while (list_cmd != NULL - && acmd_scsi_cmd(list_cmd).serial_number - < acmd_scsi_cmd(acmd).serial_number) - list_cmd = TAILQ_NEXT(list_cmd, acmd_links.tqe); - if (list_cmd != NULL) - TAILQ_INSERT_BEFORE(list_cmd, acmd, acmd_links.tqe); - else - TAILQ_INSERT_TAIL(completeq, acmd, acmd_links.tqe); + cmd->scsi_done(cmd); } static void -ahd_linux_filter_inquiry(struct ahd_softc *ahd, struct ahd_devinfo *devinfo) +ahd_linux_sem_timeout(u_long arg) { - struct scsi_inquiry_data *sid; - struct ahd_initiator_tinfo *tinfo; - struct ahd_transinfo *user; - struct ahd_transinfo *goal; - struct ahd_transinfo *curr; - struct ahd_tmode_tstate *tstate; - struct ahd_linux_device *dev; - u_int width; - u_int period; - u_int offset; - u_int ppr_options; - u_int trans_version; - u_int prot_version; + struct ahd_softc *ahd; + u_long s; - /* - * Determine if this lun actually exists. If so, - * hold on to its corresponding device structure. - * If not, make sure we release the device and - * don't bother processing the rest of this inquiry - * command. - */ - dev = ahd_linux_get_device(ahd, devinfo->channel - 'A', - devinfo->target, devinfo->lun, - /*alloc*/TRUE); + ahd = (struct ahd_softc *)arg; - sid = (struct scsi_inquiry_data *)dev->target->inq_data; - if (SID_QUAL(sid) == SID_QUAL_LU_CONNECTED) { - - dev->flags &= ~AHD_DEV_UNCONFIGURED; - } else { - dev->flags |= AHD_DEV_UNCONFIGURED; - return; + ahd_lock(ahd, &s); + if ((ahd->platform_data->flags & AHD_SCB_UP_EH_SEM) != 0) { + ahd->platform_data->flags &= ~AHD_SCB_UP_EH_SEM; + up(&ahd->platform_data->eh_sem); } - - /* - * Update our notion of this device's transfer - * negotiation capabilities. - */ - tinfo = ahd_fetch_transinfo(ahd, devinfo->channel, - devinfo->our_scsiid, - devinfo->target, &tstate); - user = &tinfo->user; - goal = &tinfo->goal; - curr = &tinfo->curr; - width = user->width; - period = user->period; - offset = user->offset; - ppr_options = user->ppr_options; - trans_version = user->transport_version; - prot_version = MIN(user->protocol_version, SID_ANSI_REV(sid)); - - /* - * Only attempt SPI3/4 once we've verified that - * the device claims to support SPI3/4 features. - */ - if (prot_version < SCSI_REV_2) - trans_version = SID_ANSI_REV(sid); - else - trans_version = SCSI_REV_2; - - if ((sid->flags & SID_WBus16) == 0) - width = MSG_EXT_WDTR_BUS_8_BIT; - if ((sid->flags & SID_Sync) == 0) { - period = 0; - offset = 0; - ppr_options = 0; - } - if ((sid->spi3data & SID_SPI_QAS) == 0) - ppr_options &= ~MSG_EXT_PPR_QAS_REQ; - if ((sid->spi3data & SID_SPI_CLOCK_DT) == 0) - ppr_options &= MSG_EXT_PPR_QAS_REQ; - if ((sid->spi3data & SID_SPI_IUS) == 0) - ppr_options &= (MSG_EXT_PPR_DT_REQ - | MSG_EXT_PPR_QAS_REQ); - - if (prot_version > SCSI_REV_2 - && ppr_options != 0) - trans_version = user->transport_version; - - ahd_validate_width(ahd, /*tinfo limit*/NULL, &width, ROLE_UNKNOWN); - ahd_find_syncrate(ahd, &period, &ppr_options, AHD_SYNCRATE_MAX); - ahd_validate_offset(ahd, /*tinfo limit*/NULL, period, - &offset, width, ROLE_UNKNOWN); - if (offset == 0 || period == 0) { - period = 0; - offset = 0; - ppr_options = 0; - } - /* Apply our filtered user settings. */ - curr->transport_version = trans_version; - curr->protocol_version = prot_version; - ahd_set_width(ahd, devinfo, width, AHD_TRANS_GOAL, /*paused*/FALSE); - ahd_set_syncrate(ahd, devinfo, period, offset, ppr_options, - AHD_TRANS_GOAL, /*paused*/FALSE); + ahd_unlock(ahd, &s); } void @@ -4388,11 +2029,6 @@ ahd_release_simq(struct ahd_softc *ahd) if (ahd->platform_data->qfrozen == 0) { unblock_reqs = 1; } - if (AHD_DV_SIMQ_FROZEN(ahd) - && ((ahd->platform_data->flags & AHD_DV_WAIT_SIMQ_RELEASE) != 0)) { - ahd->platform_data->flags &= ~AHD_DV_WAIT_SIMQ_RELEASE; - up(&ahd->platform_data->dv_sem); - } ahd_unlock(ahd, &s); /* * There is still a race here. The mid-layer @@ -4404,65 +2040,526 @@ ahd_release_simq(struct ahd_softc *ahd) scsi_unblock_requests(ahd->platform_data->host); } -static void -ahd_linux_sem_timeout(u_long arg) +static int +ahd_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) { - struct scb *scb; - struct ahd_softc *ahd; - u_long s; - - scb = (struct scb *)arg; - ahd = scb->ahd_softc; - ahd_lock(ahd, &s); - if ((scb->platform_data->flags & AHD_SCB_UP_EH_SEM) != 0) { - scb->platform_data->flags &= ~AHD_SCB_UP_EH_SEM; - up(&ahd->platform_data->eh_sem); - } - ahd_unlock(ahd, &s); -} - -static void -ahd_linux_dev_timed_unfreeze(u_long arg) -{ - struct ahd_linux_device *dev; struct ahd_softc *ahd; - u_long s; + struct ahd_linux_device *dev; + struct scb *pending_scb; + u_int saved_scbptr; + u_int active_scbptr; + u_int last_phase; + u_int saved_scsiid; + u_int cdb_byte; + int retval; + int was_paused; + int paused; + int wait; + int disconnected; + ahd_mode_state saved_modes; - dev = (struct ahd_linux_device *)arg; - ahd = dev->target->ahd; - ahd_lock(ahd, &s); - dev->flags &= ~AHD_DEV_TIMER_ACTIVE; - if (dev->qfrozen > 0) - dev->qfrozen--; - if ((dev->flags & AHD_DEV_UNCONFIGURED) != 0 - && dev->active == 0) - ahd_linux_free_device(ahd, dev); - ahd_unlock(ahd, &s); + pending_scb = NULL; + paused = FALSE; + wait = FALSE; + ahd = *(struct ahd_softc **)cmd->device->host->hostdata; + + printf("%s:%d:%d:%d: Attempting to queue a%s message:", + ahd_name(ahd), cmd->device->channel, + cmd->device->id, cmd->device->lun, + flag == SCB_ABORT ? "n ABORT" : " TARGET RESET"); + + printf("CDB:"); + for (cdb_byte = 0; cdb_byte < cmd->cmd_len; cdb_byte++) + printf(" 0x%x", cmd->cmnd[cdb_byte]); + printf("\n"); + + spin_lock_irq(&ahd->platform_data->spin_lock); + + /* + * First determine if we currently own this command. + * Start by searching the device queue. If not found + * there, check the pending_scb list. If not found + * at all, and the system wanted us to just abort the + * command, return success. + */ + dev = scsi_transport_device_data(cmd->device); + + if (dev == NULL) { + /* + * No target device for this command exists, + * so we must not still own the command. + */ + printf("%s:%d:%d:%d: Is not an active device\n", + ahd_name(ahd), cmd->device->channel, cmd->device->id, + cmd->device->lun); + retval = SUCCESS; + goto no_cmd; + } + + /* + * See if we can find a matching cmd in the pending list. + */ + LIST_FOREACH(pending_scb, &ahd->pending_scbs, pending_links) { + if (pending_scb->io_ctx == cmd) + break; + } + + if (pending_scb == NULL && flag == SCB_DEVICE_RESET) { + + /* Any SCB for this device will do for a target reset */ + LIST_FOREACH(pending_scb, &ahd->pending_scbs, pending_links) { + if (ahd_match_scb(ahd, pending_scb, cmd->device->id, + cmd->device->channel + 'A', + CAM_LUN_WILDCARD, + SCB_LIST_NULL, ROLE_INITIATOR) == 0) + break; + } + } + + if (pending_scb == NULL) { + printf("%s:%d:%d:%d: Command not found\n", + ahd_name(ahd), cmd->device->channel, cmd->device->id, + cmd->device->lun); + goto no_cmd; + } + + if ((pending_scb->flags & SCB_RECOVERY_SCB) != 0) { + /* + * We can't queue two recovery actions using the same SCB + */ + retval = FAILED; + goto done; + } + + /* + * Ensure that the card doesn't do anything + * behind our back. Also make sure that we + * didn't "just" miss an interrupt that would + * affect this cmd. + */ + was_paused = ahd_is_paused(ahd); + ahd_pause_and_flushwork(ahd); + paused = TRUE; + + if ((pending_scb->flags & SCB_ACTIVE) == 0) { + printf("%s:%d:%d:%d: Command already completed\n", + ahd_name(ahd), cmd->device->channel, cmd->device->id, + cmd->device->lun); + goto no_cmd; + } + + printf("%s: At time of recovery, card was %spaused\n", + ahd_name(ahd), was_paused ? "" : "not "); + ahd_dump_card_state(ahd); + + disconnected = TRUE; + if (flag == SCB_ABORT) { + if (ahd_search_qinfifo(ahd, cmd->device->id, + cmd->device->channel + 'A', + cmd->device->lun, + pending_scb->hscb->tag, + ROLE_INITIATOR, CAM_REQ_ABORTED, + SEARCH_COMPLETE) > 0) { + printf("%s:%d:%d:%d: Cmd aborted from QINFIFO\n", + ahd_name(ahd), cmd->device->channel, + cmd->device->id, cmd->device->lun); + retval = SUCCESS; + goto done; + } + } else if (ahd_search_qinfifo(ahd, cmd->device->id, + cmd->device->channel + 'A', + cmd->device->lun, pending_scb->hscb->tag, + ROLE_INITIATOR, /*status*/0, + SEARCH_COUNT) > 0) { + disconnected = FALSE; + } + + saved_modes = ahd_save_modes(ahd); + ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); + last_phase = ahd_inb(ahd, LASTPHASE); + saved_scbptr = ahd_get_scbptr(ahd); + active_scbptr = saved_scbptr; + if (disconnected && (ahd_inb(ahd, SEQ_FLAGS) & NOT_IDENTIFIED) == 0) { + struct scb *bus_scb; + + bus_scb = ahd_lookup_scb(ahd, active_scbptr); + if (bus_scb == pending_scb) + disconnected = FALSE; + else if (flag != SCB_ABORT + && ahd_inb(ahd, SAVED_SCSIID) == pending_scb->hscb->scsiid + && ahd_inb(ahd, SAVED_LUN) == SCB_GET_LUN(pending_scb)) + disconnected = FALSE; + } + + /* + * At this point, pending_scb is the scb associated with the + * passed in command. That command is currently active on the + * bus or is in the disconnected state. + */ + saved_scsiid = ahd_inb(ahd, SAVED_SCSIID); + if (last_phase != P_BUSFREE + && (SCB_GET_TAG(pending_scb) == active_scbptr + || (flag == SCB_DEVICE_RESET + && SCSIID_TARGET(ahd, saved_scsiid) == cmd->device->id))) { + + /* + * We're active on the bus, so assert ATN + * and hope that the target responds. + */ + pending_scb = ahd_lookup_scb(ahd, active_scbptr); + pending_scb->flags |= SCB_RECOVERY_SCB|flag; + ahd_outb(ahd, MSG_OUT, HOST_MSG); + ahd_outb(ahd, SCSISIGO, last_phase|ATNO); + printf("%s:%d:%d:%d: Device is active, asserting ATN\n", + ahd_name(ahd), cmd->device->channel, + cmd->device->id, cmd->device->lun); + wait = TRUE; + } else if (disconnected) { + + /* + * Actually re-queue this SCB in an attempt + * to select the device before it reconnects. + */ + pending_scb->flags |= SCB_RECOVERY_SCB|SCB_ABORT; + ahd_set_scbptr(ahd, SCB_GET_TAG(pending_scb)); + pending_scb->hscb->cdb_len = 0; + pending_scb->hscb->task_attribute = 0; + pending_scb->hscb->task_management = SIU_TASKMGMT_ABORT_TASK; + + if ((pending_scb->flags & SCB_PACKETIZED) != 0) { + /* + * Mark the SCB has having an outstanding + * task management function. Should the command + * complete normally before the task management + * function can be sent, the host will be notified + * to abort our requeued SCB. + */ + ahd_outb(ahd, SCB_TASK_MANAGEMENT, + pending_scb->hscb->task_management); + } else { + /* + * If non-packetized, set the MK_MESSAGE control + * bit indicating that we desire to send a message. + * We also set the disconnected flag since there is + * no guarantee that our SCB control byte matches + * the version on the card. We don't want the + * sequencer to abort the command thinking an + * unsolicited reselection occurred. + */ + pending_scb->hscb->control |= MK_MESSAGE|DISCONNECTED; + + /* + * The sequencer will never re-reference the + * in-core SCB. To make sure we are notified + * during reslection, set the MK_MESSAGE flag in + * the card's copy of the SCB. + */ + ahd_outb(ahd, SCB_CONTROL, + ahd_inb(ahd, SCB_CONTROL)|MK_MESSAGE); + } + + /* + * Clear out any entries in the QINFIFO first + * so we are the next SCB for this target + * to run. + */ + ahd_search_qinfifo(ahd, cmd->device->id, + cmd->device->channel + 'A', cmd->device->lun, + SCB_LIST_NULL, ROLE_INITIATOR, + CAM_REQUEUE_REQ, SEARCH_COMPLETE); + ahd_qinfifo_requeue_tail(ahd, pending_scb); + ahd_set_scbptr(ahd, saved_scbptr); + ahd_print_path(ahd, pending_scb); + printf("Device is disconnected, re-queuing SCB\n"); + wait = TRUE; + } else { + printf("%s:%d:%d:%d: Unable to deliver message\n", + ahd_name(ahd), cmd->device->channel, + cmd->device->id, cmd->device->lun); + retval = FAILED; + goto done; + } + +no_cmd: + /* + * Our assumption is that if we don't have the command, no + * recovery action was required, so we return success. Again, + * the semantics of the mid-layer recovery engine are not + * well defined, so this may change in time. + */ + retval = SUCCESS; +done: + if (paused) + ahd_unpause(ahd); + if (wait) { + struct timer_list timer; + int ret; + + ahd->platform_data->flags |= AHD_SCB_UP_EH_SEM; + spin_unlock_irq(&ahd->platform_data->spin_lock); + init_timer(&timer); + timer.data = (u_long)ahd; + timer.expires = jiffies + (5 * HZ); + timer.function = ahd_linux_sem_timeout; + add_timer(&timer); + printf("Recovery code sleeping\n"); + down(&ahd->platform_data->eh_sem); + printf("Recovery code awake\n"); + ret = del_timer_sync(&timer); + if (ret == 0) { + printf("Timer Expired\n"); + retval = FAILED; + } + spin_lock_irq(&ahd->platform_data->spin_lock); + } + spin_unlock_irq(&ahd->platform_data->spin_lock); + return (retval); } +static void ahd_linux_exit(void); + +static void ahd_linux_set_width(struct scsi_target *starget, int width) +{ + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); + struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata); + struct ahd_devinfo devinfo; + unsigned long flags; + + ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, + starget->channel + 'A', ROLE_INITIATOR); + ahd_lock(ahd, &flags); + ahd_set_width(ahd, &devinfo, width, AHD_TRANS_GOAL, FALSE); + ahd_unlock(ahd, &flags); +} + +static void ahd_linux_set_period(struct scsi_target *starget, int period) +{ + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); + struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata); + struct ahd_tmode_tstate *tstate; + struct ahd_initiator_tinfo *tinfo + = ahd_fetch_transinfo(ahd, + starget->channel + 'A', + shost->this_id, starget->id, &tstate); + struct ahd_devinfo devinfo; + unsigned int ppr_options = tinfo->goal.ppr_options; + unsigned long flags; + unsigned long offset = tinfo->goal.offset; + + if (offset == 0) + offset = MAX_OFFSET; + + if (period < 8) + period = 8; + if (period < 10) { + ppr_options |= MSG_EXT_PPR_DT_REQ; + if (period == 8) + ppr_options |= MSG_EXT_PPR_IU_REQ; + } + + ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, + starget->channel + 'A', ROLE_INITIATOR); + + /* all PPR requests apart from QAS require wide transfers */ + if (ppr_options & ~MSG_EXT_PPR_QAS_REQ) { + if (spi_width(starget) == 0) + ppr_options &= MSG_EXT_PPR_QAS_REQ; + } + + ahd_find_syncrate(ahd, &period, &ppr_options, AHD_SYNCRATE_MAX); + ahd_lock(ahd, &flags); + ahd_set_syncrate(ahd, &devinfo, period, offset, + ppr_options, AHD_TRANS_GOAL, FALSE); + ahd_unlock(ahd, &flags); +} + +static void ahd_linux_set_offset(struct scsi_target *starget, int offset) +{ + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); + struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata); + struct ahd_tmode_tstate *tstate; + struct ahd_initiator_tinfo *tinfo + = ahd_fetch_transinfo(ahd, + starget->channel + 'A', + shost->this_id, starget->id, &tstate); + struct ahd_devinfo devinfo; + unsigned int ppr_options = 0; + unsigned int period = 0; + unsigned long flags; + + ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, + starget->channel + 'A', ROLE_INITIATOR); + if (offset != 0) { + period = tinfo->goal.period; + ppr_options = tinfo->goal.ppr_options; + ahd_find_syncrate(ahd, &period, &ppr_options, AHD_SYNCRATE_MAX); + } + ahd_lock(ahd, &flags); + ahd_set_syncrate(ahd, &devinfo, period, offset, ppr_options, + AHD_TRANS_GOAL, FALSE); + ahd_unlock(ahd, &flags); +} + +static void ahd_linux_set_dt(struct scsi_target *starget, int dt) +{ + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); + struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata); + struct ahd_tmode_tstate *tstate; + struct ahd_initiator_tinfo *tinfo + = ahd_fetch_transinfo(ahd, + starget->channel + 'A', + shost->this_id, starget->id, &tstate); + struct ahd_devinfo devinfo; + unsigned int ppr_options = tinfo->goal.ppr_options + & ~MSG_EXT_PPR_DT_REQ; + unsigned int period = tinfo->goal.period; + unsigned long flags; + + if (dt) { + ppr_options |= MSG_EXT_PPR_DT_REQ; + if (period > 9) + period = 9; /* at least 12.5ns for DT */ + } else if (period <= 9) + period = 10; /* If resetting DT, period must be >= 25ns */ + + ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, + starget->channel + 'A', ROLE_INITIATOR); + ahd_find_syncrate(ahd, &period, &ppr_options, + dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); + ahd_lock(ahd, &flags); + ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, + ppr_options, AHD_TRANS_GOAL, FALSE); + ahd_unlock(ahd, &flags); +} + +static void ahd_linux_set_qas(struct scsi_target *starget, int qas) +{ + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); + struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata); + struct ahd_tmode_tstate *tstate; + struct ahd_initiator_tinfo *tinfo + = ahd_fetch_transinfo(ahd, + starget->channel + 'A', + shost->this_id, starget->id, &tstate); + struct ahd_devinfo devinfo; + unsigned int ppr_options = tinfo->goal.ppr_options + & ~MSG_EXT_PPR_QAS_REQ; + unsigned int period = tinfo->goal.period; + unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ; + unsigned long flags; + + if (qas) + ppr_options |= MSG_EXT_PPR_QAS_REQ; + + ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, + starget->channel + 'A', ROLE_INITIATOR); + ahd_find_syncrate(ahd, &period, &ppr_options, + dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); + ahd_lock(ahd, &flags); + ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, + ppr_options, AHD_TRANS_GOAL, FALSE); + ahd_unlock(ahd, &flags); +} + +static void ahd_linux_set_iu(struct scsi_target *starget, int iu) +{ + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); + struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata); + struct ahd_tmode_tstate *tstate; + struct ahd_initiator_tinfo *tinfo + = ahd_fetch_transinfo(ahd, + starget->channel + 'A', + shost->this_id, starget->id, &tstate); + struct ahd_devinfo devinfo; + unsigned int ppr_options = tinfo->goal.ppr_options + & ~MSG_EXT_PPR_IU_REQ; + unsigned int period = tinfo->goal.period; + unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ; + unsigned long flags; + + if (iu) + ppr_options |= MSG_EXT_PPR_IU_REQ; + + ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, + starget->channel + 'A', ROLE_INITIATOR); + ahd_find_syncrate(ahd, &period, &ppr_options, + dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); + ahd_lock(ahd, &flags); + ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, + ppr_options, AHD_TRANS_GOAL, FALSE); + ahd_unlock(ahd, &flags); +} + +static void ahd_linux_set_rd_strm(struct scsi_target *starget, int rdstrm) +{ + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); + struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata); + struct ahd_tmode_tstate *tstate; + struct ahd_initiator_tinfo *tinfo + = ahd_fetch_transinfo(ahd, + starget->channel + 'A', + shost->this_id, starget->id, &tstate); + struct ahd_devinfo devinfo; + unsigned int ppr_options = tinfo->goal.ppr_options + & ~MSG_EXT_PPR_RD_STRM; + unsigned int period = tinfo->goal.period; + unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ; + unsigned long flags; + + if (rdstrm) + ppr_options |= MSG_EXT_PPR_RD_STRM; + + ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, + starget->channel + 'A', ROLE_INITIATOR); + ahd_find_syncrate(ahd, &period, &ppr_options, + dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); + ahd_lock(ahd, &flags); + ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, + ppr_options, AHD_TRANS_GOAL, FALSE); + ahd_unlock(ahd, &flags); +} + +static struct spi_function_template ahd_linux_transport_functions = { + .set_offset = ahd_linux_set_offset, + .show_offset = 1, + .set_period = ahd_linux_set_period, + .show_period = 1, + .set_width = ahd_linux_set_width, + .show_width = 1, + .set_dt = ahd_linux_set_dt, + .show_dt = 1, + .set_iu = ahd_linux_set_iu, + .show_iu = 1, + .set_qas = ahd_linux_set_qas, + .show_qas = 1, + .set_rd_strm = ahd_linux_set_rd_strm, + .show_rd_strm = 1, +}; + + + static int __init ahd_linux_init(void) { - return ahd_linux_detect(&aic79xx_driver_template); + ahd_linux_transport_template = spi_attach_transport(&ahd_linux_transport_functions); + if (!ahd_linux_transport_template) + return -ENODEV; + scsi_transport_reserve_target(ahd_linux_transport_template, + sizeof(struct ahd_linux_target)); + scsi_transport_reserve_device(ahd_linux_transport_template, + sizeof(struct ahd_linux_device)); + if (ahd_linux_detect(&aic79xx_driver_template) > 0) + return 0; + spi_release_transport(ahd_linux_transport_template); + ahd_linux_exit(); + return -ENODEV; } static void __exit ahd_linux_exit(void) { - struct ahd_softc *ahd; - - /* - * Shutdown DV threads before going into the SCSI mid-layer. - * This avoids situations where the mid-layer locks the entire - * kernel so that waiting for our DV threads to exit leads - * to deadlock. - */ - TAILQ_FOREACH(ahd, &ahd_tailq, links) { - - ahd_linux_kill_dv_thread(ahd); - } - ahd_linux_pci_exit(); + spi_release_transport(ahd_linux_transport_template); } module_init(ahd_linux_init); diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h index 792e97fef5b8..46edcf3e4e62 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.h +++ b/drivers/scsi/aic7xxx/aic79xx_osm.h @@ -42,6 +42,7 @@ #ifndef _AIC79XX_LINUX_H_ #define _AIC79XX_LINUX_H_ +#include #include #include #include @@ -49,18 +50,23 @@ #include #include #include +#include #include +#include #include #include -#include /* For tasklet support. */ -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include /* Core SCSI definitions */ #define AIC_LIB_PREFIX ahd -#include "scsi.h" -#include /* Name space conflict with BSD queue macros */ #ifdef LIST_HEAD @@ -95,7 +101,7 @@ /************************* Forward Declarations *******************************/ struct ahd_softc; typedef struct pci_dev *ahd_dev_softc_t; -typedef Scsi_Cmnd *ahd_io_ctx_t; +typedef struct scsi_cmnd *ahd_io_ctx_t; /******************************* Byte Order ***********************************/ #define ahd_htobe16(x) cpu_to_be16(x) @@ -115,7 +121,7 @@ typedef Scsi_Cmnd *ahd_io_ctx_t; /************************* Configuration Data *********************************/ extern uint32_t aic79xx_allow_memio; extern int aic79xx_detect_complete; -extern Scsi_Host_Template aic79xx_driver_template; +extern struct scsi_host_template aic79xx_driver_template; /***************************** Bus Space/DMA **********************************/ @@ -145,11 +151,7 @@ struct ahd_linux_dma_tag }; typedef struct ahd_linux_dma_tag* bus_dma_tag_t; -struct ahd_linux_dmamap -{ - dma_addr_t bus_addr; -}; -typedef struct ahd_linux_dmamap* bus_dmamap_t; +typedef dma_addr_t bus_dmamap_t; typedef int bus_dma_filter_t(void*, dma_addr_t); typedef void bus_dmamap_callback_t(void *, bus_dma_segment_t *, int, int); @@ -226,12 +228,12 @@ typedef struct timer_list ahd_timer_t; #define ahd_timer_init init_timer #define ahd_timer_stop del_timer_sync typedef void ahd_linux_callback_t (u_long); -static __inline void ahd_timer_reset(ahd_timer_t *timer, u_int usec, +static __inline void ahd_timer_reset(ahd_timer_t *timer, int usec, ahd_callback_t *func, void *arg); static __inline void ahd_scb_timer_reset(struct scb *scb, u_int usec); static __inline void -ahd_timer_reset(ahd_timer_t *timer, u_int usec, ahd_callback_t *func, void *arg) +ahd_timer_reset(ahd_timer_t *timer, int usec, ahd_callback_t *func, void *arg) { struct ahd_softc *ahd; @@ -382,62 +384,12 @@ struct ahd_linux_device { */ u_int commands_since_idle_or_otag; #define AHD_OTAG_THRESH 500 - - int lun; - Scsi_Device *scsi_device; - struct ahd_linux_target *target; }; -typedef enum { - AHD_DV_REQUIRED = 0x01, - AHD_INQ_VALID = 0x02, - AHD_BASIC_DV = 0x04, - AHD_ENHANCED_DV = 0x08 -} ahd_linux_targ_flags; - -/* DV States */ -typedef enum { - AHD_DV_STATE_EXIT = 0, - AHD_DV_STATE_INQ_SHORT_ASYNC, - AHD_DV_STATE_INQ_ASYNC, - AHD_DV_STATE_INQ_ASYNC_VERIFY, - AHD_DV_STATE_TUR, - AHD_DV_STATE_REBD, - AHD_DV_STATE_INQ_VERIFY, - AHD_DV_STATE_WEB, - AHD_DV_STATE_REB, - AHD_DV_STATE_SU, - AHD_DV_STATE_BUSY -} ahd_dv_state; - struct ahd_linux_target { - struct ahd_linux_device *devices[AHD_NUM_LUNS]; - int channel; - int target; - int refcount; + struct scsi_device *sdev[AHD_NUM_LUNS]; struct ahd_transinfo last_tinfo; struct ahd_softc *ahd; - ahd_linux_targ_flags flags; - struct scsi_inquiry_data *inq_data; - /* - * The next "fallback" period to use for narrow/wide transfers. - */ - uint8_t dv_next_narrow_period; - uint8_t dv_next_wide_period; - uint8_t dv_max_width; - uint8_t dv_max_ppr_options; - uint8_t dv_last_ppr_options; - u_int dv_echo_size; - ahd_dv_state dv_state; - u_int dv_state_retry; - uint8_t *dv_buffer; - uint8_t *dv_buffer1; - - /* - * Cumulative counter of errors. - */ - u_long errors_detected; - u_long cmds_since_error; }; /********************* Definitions Required by the Core ***********************/ @@ -452,16 +404,11 @@ struct ahd_linux_target { /* * Per-SCB OSM storage. */ -typedef enum { - AHD_SCB_UP_EH_SEM = 0x1 -} ahd_linux_scb_flags; - struct scb_platform_data { struct ahd_linux_device *dev; dma_addr_t buf_busaddr; uint32_t xfer_len; uint32_t sense_resid; /* Auto-Sense residual */ - ahd_linux_scb_flags flags; }; /* @@ -470,42 +417,24 @@ struct scb_platform_data { * alignment restrictions of the various platforms supported by * this driver. */ -typedef enum { - AHD_DV_WAIT_SIMQ_EMPTY = 0x01, - AHD_DV_WAIT_SIMQ_RELEASE = 0x02, - AHD_DV_ACTIVE = 0x04, - AHD_DV_SHUTDOWN = 0x08, - AHD_RUN_CMPLT_Q_TIMER = 0x10 -} ahd_linux_softc_flags; - -TAILQ_HEAD(ahd_completeq, ahd_cmd); - struct ahd_platform_data { /* * Fields accessed from interrupt context. */ - struct ahd_linux_target *targets[AHD_NUM_TARGETS]; - struct ahd_completeq completeq; + struct scsi_target *starget[AHD_NUM_TARGETS]; spinlock_t spin_lock; u_int qfrozen; - pid_t dv_pid; - struct timer_list completeq_timer; struct timer_list reset_timer; - struct timer_list stats_timer; struct semaphore eh_sem; - struct semaphore dv_sem; - struct semaphore dv_cmd_sem; /* XXX This needs to be in - * the target struct - */ - struct scsi_device *dv_scsi_dev; struct Scsi_Host *host; /* pointer to scsi host */ #define AHD_LINUX_NOIRQ ((uint32_t)~0) uint32_t irq; /* IRQ for this adapter */ uint32_t bios_address; uint32_t mem_busaddr; /* Mem Base Addr */ uint64_t hw_dma_mask; - ahd_linux_softc_flags flags; +#define AHD_SCB_UP_EH_SEM 0x1 + uint32_t flags; }; /************************** OS Utility Wrappers *******************************/ @@ -622,7 +551,7 @@ ahd_insb(struct ahd_softc * ahd, long port, uint8_t *array, int count) /**************************** Initialization **********************************/ int ahd_linux_register_host(struct ahd_softc *, - Scsi_Host_Template *); + struct scsi_host_template *); uint64_t ahd_linux_get_memsize(void); @@ -643,17 +572,6 @@ static __inline void ahd_lockinit(struct ahd_softc *); static __inline void ahd_lock(struct ahd_softc *, unsigned long *flags); static __inline void ahd_unlock(struct ahd_softc *, unsigned long *flags); -/* Lock acquisition and release of the above lock in midlayer entry points. */ -static __inline void ahd_midlayer_entrypoint_lock(struct ahd_softc *, - unsigned long *flags); -static __inline void ahd_midlayer_entrypoint_unlock(struct ahd_softc *, - unsigned long *flags); - -/* Lock held during command compeletion to the upper layer */ -static __inline void ahd_done_lockinit(struct ahd_softc *); -static __inline void ahd_done_lock(struct ahd_softc *, unsigned long *flags); -static __inline void ahd_done_unlock(struct ahd_softc *, unsigned long *flags); - /* Lock held during ahd_list manipulation and ahd softc frees */ extern spinlock_t ahd_list_spinlock; static __inline void ahd_list_lockinit(void); @@ -678,57 +596,6 @@ ahd_unlock(struct ahd_softc *ahd, unsigned long *flags) spin_unlock_irqrestore(&ahd->platform_data->spin_lock, *flags); } -static __inline void -ahd_midlayer_entrypoint_lock(struct ahd_softc *ahd, unsigned long *flags) -{ - /* - * In 2.5.X and some 2.4.X versions, the midlayer takes our - * lock just before calling us, so we avoid locking again. - * For other kernel versions, the io_request_lock is taken - * just before our entry point is called. In this case, we - * trade the io_request_lock for our per-softc lock. - */ -#if AHD_SCSI_HAS_HOST_LOCK == 0 - spin_unlock(&io_request_lock); - spin_lock(&ahd->platform_data->spin_lock); -#endif -} - -static __inline void -ahd_midlayer_entrypoint_unlock(struct ahd_softc *ahd, unsigned long *flags) -{ -#if AHD_SCSI_HAS_HOST_LOCK == 0 - spin_unlock(&ahd->platform_data->spin_lock); - spin_lock(&io_request_lock); -#endif -} - -static __inline void -ahd_done_lockinit(struct ahd_softc *ahd) -{ - /* - * In 2.5.X, our own lock is held during completions. - * In previous versions, the io_request_lock is used. - * In either case, we can't initialize this lock again. - */ -} - -static __inline void -ahd_done_lock(struct ahd_softc *ahd, unsigned long *flags) -{ -#if AHD_SCSI_HAS_HOST_LOCK == 0 - spin_lock(&io_request_lock); -#endif -} - -static __inline void -ahd_done_unlock(struct ahd_softc *ahd, unsigned long *flags) -{ -#if AHD_SCSI_HAS_HOST_LOCK == 0 - spin_unlock(&io_request_lock); -#endif -} - static __inline void ahd_list_lockinit(void) { @@ -909,20 +776,14 @@ ahd_flush_device_writes(struct ahd_softc *ahd) int ahd_linux_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int); -/*************************** Domain Validation ********************************/ -#define AHD_DV_CMD(cmd) ((cmd)->scsi_done == ahd_linux_dv_complete) -#define AHD_DV_SIMQ_FROZEN(ahd) \ - ((((ahd)->platform_data->flags & AHD_DV_ACTIVE) != 0) \ - && (ahd)->platform_data->qfrozen == 1) - /*********************** Transaction Access Wrappers **************************/ -static __inline void ahd_cmd_set_transaction_status(Scsi_Cmnd *, uint32_t); +static __inline void ahd_cmd_set_transaction_status(struct scsi_cmnd *, uint32_t); static __inline void ahd_set_transaction_status(struct scb *, uint32_t); -static __inline void ahd_cmd_set_scsi_status(Scsi_Cmnd *, uint32_t); +static __inline void ahd_cmd_set_scsi_status(struct scsi_cmnd *, uint32_t); static __inline void ahd_set_scsi_status(struct scb *, uint32_t); -static __inline uint32_t ahd_cmd_get_transaction_status(Scsi_Cmnd *cmd); +static __inline uint32_t ahd_cmd_get_transaction_status(struct scsi_cmnd *cmd); static __inline uint32_t ahd_get_transaction_status(struct scb *); -static __inline uint32_t ahd_cmd_get_scsi_status(Scsi_Cmnd *cmd); +static __inline uint32_t ahd_cmd_get_scsi_status(struct scsi_cmnd *cmd); static __inline uint32_t ahd_get_scsi_status(struct scb *); static __inline void ahd_set_transaction_tag(struct scb *, int, u_int); static __inline u_long ahd_get_transfer_length(struct scb *); @@ -941,7 +802,7 @@ static __inline void ahd_platform_scb_free(struct ahd_softc *ahd, static __inline void ahd_freeze_scb(struct scb *scb); static __inline -void ahd_cmd_set_transaction_status(Scsi_Cmnd *cmd, uint32_t status) +void ahd_cmd_set_transaction_status(struct scsi_cmnd *cmd, uint32_t status) { cmd->result &= ~(CAM_STATUS_MASK << 16); cmd->result |= status << 16; @@ -954,7 +815,7 @@ void ahd_set_transaction_status(struct scb *scb, uint32_t status) } static __inline -void ahd_cmd_set_scsi_status(Scsi_Cmnd *cmd, uint32_t status) +void ahd_cmd_set_scsi_status(struct scsi_cmnd *cmd, uint32_t status) { cmd->result &= ~0xFFFF; cmd->result |= status; @@ -967,7 +828,7 @@ void ahd_set_scsi_status(struct scb *scb, uint32_t status) } static __inline -uint32_t ahd_cmd_get_transaction_status(Scsi_Cmnd *cmd) +uint32_t ahd_cmd_get_transaction_status(struct scsi_cmnd *cmd) { return ((cmd->result >> 16) & CAM_STATUS_MASK); } @@ -979,7 +840,7 @@ uint32_t ahd_get_transaction_status(struct scb *scb) } static __inline -uint32_t ahd_cmd_get_scsi_status(Scsi_Cmnd *cmd) +uint32_t ahd_cmd_get_scsi_status(struct scsi_cmnd *cmd) { return (cmd->result & 0xFFFF); } diff --git a/drivers/scsi/aic7xxx/aic79xx_proc.c b/drivers/scsi/aic7xxx/aic79xx_proc.c index 9c631a494ed2..2058aa9b5c80 100644 --- a/drivers/scsi/aic7xxx/aic79xx_proc.c +++ b/drivers/scsi/aic7xxx/aic79xx_proc.c @@ -49,7 +49,7 @@ static void ahd_dump_target_state(struct ahd_softc *ahd, u_int our_id, char channel, u_int target_id, u_int target_offset); static void ahd_dump_device_state(struct info_str *info, - struct ahd_linux_device *dev); + struct scsi_device *sdev); static int ahd_proc_write_seeprom(struct ahd_softc *ahd, char *buffer, int length); @@ -167,6 +167,7 @@ ahd_dump_target_state(struct ahd_softc *ahd, struct info_str *info, u_int target_offset) { struct ahd_linux_target *targ; + struct scsi_target *starget; struct ahd_initiator_tinfo *tinfo; struct ahd_tmode_tstate *tstate; int lun; @@ -176,7 +177,8 @@ ahd_dump_target_state(struct ahd_softc *ahd, struct info_str *info, copy_info(info, "Target %d Negotiation Settings\n", target_id); copy_info(info, "\tUser: "); ahd_format_transinfo(info, &tinfo->user); - targ = ahd->platform_data->targets[target_offset]; + starget = ahd->platform_data->starget[target_offset]; + targ = scsi_transport_target_data(starget); if (targ == NULL) return; @@ -184,12 +186,11 @@ ahd_dump_target_state(struct ahd_softc *ahd, struct info_str *info, ahd_format_transinfo(info, &tinfo->goal); copy_info(info, "\tCurr: "); ahd_format_transinfo(info, &tinfo->curr); - copy_info(info, "\tTransmission Errors %ld\n", targ->errors_detected); for (lun = 0; lun < AHD_NUM_LUNS; lun++) { - struct ahd_linux_device *dev; + struct scsi_device *dev; - dev = targ->devices[lun]; + dev = targ->sdev[lun]; if (dev == NULL) continue; @@ -199,10 +200,13 @@ ahd_dump_target_state(struct ahd_softc *ahd, struct info_str *info, } static void -ahd_dump_device_state(struct info_str *info, struct ahd_linux_device *dev) +ahd_dump_device_state(struct info_str *info, struct scsi_device *sdev) { + struct ahd_linux_device *dev = scsi_transport_device_data(sdev); + copy_info(info, "\tChannel %c Target %d Lun %d Settings\n", - dev->target->channel + 'A', dev->target->target, dev->lun); + sdev->sdev_target->channel + 'A', + sdev->sdev_target->id, sdev->lun); copy_info(info, "\t\tCommands Queued %ld\n", dev->commands_issued); copy_info(info, "\t\tCommands Active %d\n", dev->active); From a4b53a11806f5c0824eb4115b1de8206ed7bb89a Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Mon, 1 Aug 2005 09:52:56 +0200 Subject: [PATCH 026/114] [SCSI] aic79xx: DV parameter settings This patch updates various scsi_transport_spi parameters with the actual parameters used by the driver internally. Domain Validation for all devices should now work properly. Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic79xx_osm.c | 231 +++++++++++++++++++++++++++-- 1 file changed, 218 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index 70997ca28baa..cf8e0ca830a2 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -1636,9 +1636,9 @@ ahd_send_async(struct ahd_softc *ahd, char channel, spi_period(starget) = tinfo->curr.period; spi_width(starget) = tinfo->curr.width; spi_offset(starget) = tinfo->curr.offset; - spi_dt(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_DT_REQ; - spi_qas(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_QAS_REQ; - spi_iu(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ; + spi_dt(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_DT_REQ ? 1 : 0; + spi_qas(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_QAS_REQ ? 1 : 0; + spi_iu(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ ? 1 : 0; spi_display_xfer_agreement(starget); break; } @@ -2318,6 +2318,18 @@ ahd_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) static void ahd_linux_exit(void); +static void ahd_linux_set_xferflags(struct scsi_target *starget, unsigned int ppr_options, unsigned int period) +{ + spi_qas(starget) = (ppr_options & MSG_EXT_PPR_QAS_REQ)? 1 : 0; + spi_dt(starget) = (ppr_options & MSG_EXT_PPR_DT_REQ)? 1 : 0; + spi_iu(starget) = (ppr_options & MSG_EXT_PPR_IU_REQ) ? 1 : 0; + spi_rd_strm(starget) = (ppr_options & MSG_EXT_PPR_RD_STRM) ? 1 : 0; + spi_wr_flow(starget) = (ppr_options & MSG_EXT_PPR_WR_FLOW) ? 1 : 0; + spi_pcomp_en(starget) = (ppr_options & MSG_EXT_PPR_PCOMP_EN) ? 1 : 0; + spi_rti(starget) = (ppr_options & MSG_EXT_PPR_RTI) ? 1 : 0; + spi_period(starget) = period; +} + static void ahd_linux_set_width(struct scsi_target *starget, int width) { struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); @@ -2343,9 +2355,14 @@ static void ahd_linux_set_period(struct scsi_target *starget, int period) shost->this_id, starget->id, &tstate); struct ahd_devinfo devinfo; unsigned int ppr_options = tinfo->goal.ppr_options; + unsigned int dt; unsigned long flags; unsigned long offset = tinfo->goal.offset; +#ifdef AHD_DEBUG + if ((ahd_debug & AHD_SHOW_DV) != 0) + printf("%s: set period to %d\n", ahd_name(ahd), period); +#endif if (offset == 0) offset = MAX_OFFSET; @@ -2357,6 +2374,8 @@ static void ahd_linux_set_period(struct scsi_target *starget, int period) ppr_options |= MSG_EXT_PPR_IU_REQ; } + dt = ppr_options & MSG_EXT_PPR_DT_REQ; + ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, starget->channel + 'A', ROLE_INITIATOR); @@ -2366,7 +2385,11 @@ static void ahd_linux_set_period(struct scsi_target *starget, int period) ppr_options &= MSG_EXT_PPR_QAS_REQ; } - ahd_find_syncrate(ahd, &period, &ppr_options, AHD_SYNCRATE_MAX); + ahd_find_syncrate(ahd, &period, &ppr_options, + dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); + + ahd_linux_set_xferflags(starget, ppr_options, period); + ahd_lock(ahd, &flags); ahd_set_syncrate(ahd, &devinfo, period, offset, ppr_options, AHD_TRANS_GOAL, FALSE); @@ -2385,15 +2408,24 @@ static void ahd_linux_set_offset(struct scsi_target *starget, int offset) struct ahd_devinfo devinfo; unsigned int ppr_options = 0; unsigned int period = 0; + unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ; unsigned long flags; +#ifdef AHD_DEBUG + if ((ahd_debug & AHD_SHOW_DV) != 0) + printf("%s: set offset to %d\n", ahd_name(ahd), offset); +#endif + ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, starget->channel + 'A', ROLE_INITIATOR); if (offset != 0) { period = tinfo->goal.period; ppr_options = tinfo->goal.ppr_options; - ahd_find_syncrate(ahd, &period, &ppr_options, AHD_SYNCRATE_MAX); + ahd_find_syncrate(ahd, &period, &ppr_options, + dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); } + ahd_linux_set_xferflags(starget, ppr_options, period); + ahd_lock(ahd, &flags); ahd_set_syncrate(ahd, &devinfo, period, offset, ppr_options, AHD_TRANS_GOAL, FALSE); @@ -2415,17 +2447,28 @@ static void ahd_linux_set_dt(struct scsi_target *starget, int dt) unsigned int period = tinfo->goal.period; unsigned long flags; +#ifdef AHD_DEBUG + if ((ahd_debug & AHD_SHOW_DV) != 0) + printf("%s: %s DT\n", ahd_name(ahd), + dt ? "enabling" : "disabling"); +#endif if (dt) { ppr_options |= MSG_EXT_PPR_DT_REQ; if (period > 9) period = 9; /* at least 12.5ns for DT */ - } else if (period <= 9) - period = 10; /* If resetting DT, period must be >= 25ns */ - + } else { + if (period <= 9) + period = 10; /* If resetting DT, period must be >= 25ns */ + /* IU is invalid without DT set */ + ppr_options &= ~MSG_EXT_PPR_IU_REQ; + } ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, starget->channel + 'A', ROLE_INITIATOR); ahd_find_syncrate(ahd, &period, &ppr_options, dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); + + ahd_linux_set_xferflags(starget, ppr_options, period); + ahd_lock(ahd, &flags); ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, ppr_options, AHD_TRANS_GOAL, FALSE); @@ -2445,16 +2488,28 @@ static void ahd_linux_set_qas(struct scsi_target *starget, int qas) unsigned int ppr_options = tinfo->goal.ppr_options & ~MSG_EXT_PPR_QAS_REQ; unsigned int period = tinfo->goal.period; - unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ; + unsigned int dt; unsigned long flags; - if (qas) - ppr_options |= MSG_EXT_PPR_QAS_REQ; +#ifdef AHD_DEBUG + if ((ahd_debug & AHD_SHOW_DV) != 0) + printf("%s: %s QAS\n", ahd_name(ahd), + qas ? "enabling" : "disabling"); +#endif + + if (qas) { + ppr_options |= MSG_EXT_PPR_QAS_REQ; + } + + dt = ppr_options & MSG_EXT_PPR_DT_REQ; ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, starget->channel + 'A', ROLE_INITIATOR); ahd_find_syncrate(ahd, &period, &ppr_options, dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); + + spi_qas(starget) = (ppr_options & MSG_EXT_PPR_QAS_REQ)? 1 : 0; + ahd_lock(ahd, &flags); ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, ppr_options, AHD_TRANS_GOAL, FALSE); @@ -2474,16 +2529,29 @@ static void ahd_linux_set_iu(struct scsi_target *starget, int iu) unsigned int ppr_options = tinfo->goal.ppr_options & ~MSG_EXT_PPR_IU_REQ; unsigned int period = tinfo->goal.period; - unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ; + unsigned int dt; unsigned long flags; - if (iu) +#ifdef AHD_DEBUG + if ((ahd_debug & AHD_SHOW_DV) != 0) + printf("%s: %s IU\n", ahd_name(ahd), + iu ? "enabling" : "disabling"); +#endif + + if (iu) { ppr_options |= MSG_EXT_PPR_IU_REQ; + ppr_options |= MSG_EXT_PPR_DT_REQ; /* IU requires DT */ + } + + dt = ppr_options & MSG_EXT_PPR_DT_REQ; ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, starget->channel + 'A', ROLE_INITIATOR); ahd_find_syncrate(ahd, &period, &ppr_options, dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); + + ahd_linux_set_xferflags(starget, ppr_options, period); + ahd_lock(ahd, &flags); ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, ppr_options, AHD_TRANS_GOAL, FALSE); @@ -2506,6 +2574,12 @@ static void ahd_linux_set_rd_strm(struct scsi_target *starget, int rdstrm) unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ; unsigned long flags; +#ifdef AHD_DEBUG + if ((ahd_debug & AHD_SHOW_DV) != 0) + printf("%s: %s Read Streaming\n", ahd_name(ahd), + rdstrm ? "enabling" : "disabling"); +#endif + if (rdstrm) ppr_options |= MSG_EXT_PPR_RD_STRM; @@ -2513,6 +2587,131 @@ static void ahd_linux_set_rd_strm(struct scsi_target *starget, int rdstrm) starget->channel + 'A', ROLE_INITIATOR); ahd_find_syncrate(ahd, &period, &ppr_options, dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); + + spi_rd_strm(starget) = (ppr_options & MSG_EXT_PPR_RD_STRM) ? 1 : 0; + + ahd_lock(ahd, &flags); + ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, + ppr_options, AHD_TRANS_GOAL, FALSE); + ahd_unlock(ahd, &flags); +} + +static void ahd_linux_set_wr_flow(struct scsi_target *starget, int wrflow) +{ + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); + struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata); + struct ahd_tmode_tstate *tstate; + struct ahd_initiator_tinfo *tinfo + = ahd_fetch_transinfo(ahd, + starget->channel + 'A', + shost->this_id, starget->id, &tstate); + struct ahd_devinfo devinfo; + unsigned int ppr_options = tinfo->goal.ppr_options + & ~MSG_EXT_PPR_WR_FLOW; + unsigned int period = tinfo->goal.period; + unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ; + unsigned long flags; + +#ifdef AHD_DEBUG + if ((ahd_debug & AHD_SHOW_DV) != 0) + printf("%s: %s Write Flow Control\n", ahd_name(ahd), + wrflow ? "enabling" : "disabling"); +#endif + + if (wrflow) + ppr_options |= MSG_EXT_PPR_WR_FLOW; + + ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, + starget->channel + 'A', ROLE_INITIATOR); + ahd_find_syncrate(ahd, &period, &ppr_options, + dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); + + spi_wr_flow(starget) = (ppr_options & MSG_EXT_PPR_WR_FLOW) ? 1 : 0; + + ahd_lock(ahd, &flags); + ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, + ppr_options, AHD_TRANS_GOAL, FALSE); + ahd_unlock(ahd, &flags); +} + +static void ahd_linux_set_rti(struct scsi_target *starget, int rti) +{ + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); + struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata); + struct ahd_tmode_tstate *tstate; + struct ahd_initiator_tinfo *tinfo + = ahd_fetch_transinfo(ahd, + starget->channel + 'A', + shost->this_id, starget->id, &tstate); + struct ahd_devinfo devinfo; + unsigned int ppr_options = tinfo->goal.ppr_options + & ~MSG_EXT_PPR_RTI; + unsigned int period = tinfo->goal.period; + unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ; + unsigned long flags; + + if ((ahd->features & AHD_RTI) == 0) { +#ifdef AHD_DEBUG + if ((ahd_debug & AHD_SHOW_DV) != 0) + printf("%s: RTI not available\n", ahd_name(ahd)); +#endif + return; + } + +#ifdef AHD_DEBUG + if ((ahd_debug & AHD_SHOW_DV) != 0) + printf("%s: %s RTI\n", ahd_name(ahd), + rti ? "enabling" : "disabling"); +#endif + + if (rti) + ppr_options |= MSG_EXT_PPR_RTI; + + ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, + starget->channel + 'A', ROLE_INITIATOR); + ahd_find_syncrate(ahd, &period, &ppr_options, + dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); + + spi_rti(starget) = (ppr_options & MSG_EXT_PPR_RTI) ? 1 : 0; + + ahd_lock(ahd, &flags); + ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, + ppr_options, AHD_TRANS_GOAL, FALSE); + ahd_unlock(ahd, &flags); +} + +static void ahd_linux_set_pcomp_en(struct scsi_target *starget, int pcomp) +{ + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); + struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata); + struct ahd_tmode_tstate *tstate; + struct ahd_initiator_tinfo *tinfo + = ahd_fetch_transinfo(ahd, + starget->channel + 'A', + shost->this_id, starget->id, &tstate); + struct ahd_devinfo devinfo; + unsigned int ppr_options = tinfo->goal.ppr_options + & ~MSG_EXT_PPR_PCOMP_EN; + unsigned int period = tinfo->goal.period; + unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ; + unsigned long flags; + +#ifdef AHD_DEBUG + if ((ahd_debug & AHD_SHOW_DV) != 0) + printf("%s: %s Precompensation\n", ahd_name(ahd), + pcomp ? "Enable" : "Disable"); +#endif + + if (pcomp) + ppr_options |= MSG_EXT_PPR_PCOMP_EN; + + ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, + starget->channel + 'A', ROLE_INITIATOR); + ahd_find_syncrate(ahd, &period, &ppr_options, + dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); + + spi_pcomp_en(starget) = (ppr_options & MSG_EXT_PPR_PCOMP_EN) ? 1 : 0; + ahd_lock(ahd, &flags); ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, ppr_options, AHD_TRANS_GOAL, FALSE); @@ -2534,6 +2733,12 @@ static struct spi_function_template ahd_linux_transport_functions = { .show_qas = 1, .set_rd_strm = ahd_linux_set_rd_strm, .show_rd_strm = 1, + .set_wr_flow = ahd_linux_set_wr_flow, + .show_wr_flow = 1, + .set_rti = ahd_linux_set_rti, + .show_rti = 1, + .set_pcomp_en = ahd_linux_set_pcomp_en, + .show_pcomp_en = 1, }; From 3f40d7d6eaadecd48f6d1c0c4a5ad414b992260e Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Wed, 3 Aug 2005 13:25:10 -0500 Subject: [PATCH 027/114] [SCSI] aic79xx: fix up transport settings There's a slight problem in the way you've done the transport parameters; reading from the variables actually produces the current settings, not the ones you just set (and there's usually a lag because devices don't renegotiate until the next command goes over the bus). If you set the bit immediately, you get into the situation where the transport parameters report something as being set even if the drive cannot support it. I patched the driver to do it this way and also corrected a panic in the proc routines. Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic79xx_osm.c | 39 +++++++---------------------- drivers/scsi/aic7xxx/aic79xx_proc.c | 4 +-- 2 files changed, 11 insertions(+), 32 deletions(-) diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index cf8e0ca830a2..10a2570ca387 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -1624,7 +1624,11 @@ ahd_send_async(struct ahd_softc *ahd, char channel, target_ppr_options = (spi_dt(starget) ? MSG_EXT_PPR_DT_REQ : 0) + (spi_qas(starget) ? MSG_EXT_PPR_QAS_REQ : 0) - + (spi_iu(starget) ? MSG_EXT_PPR_IU_REQ : 0); + + (spi_iu(starget) ? MSG_EXT_PPR_IU_REQ : 0) + + (spi_rd_strm(starget) ? MSG_EXT_PPR_RD_STRM : 0) + + (spi_pcomp_en(starget) ? MSG_EXT_PPR_PCOMP_EN : 0) + + (spi_rti(starget) ? MSG_EXT_PPR_RTI : 0) + + (spi_wr_flow(starget) ? MSG_EXT_PPR_WR_FLOW : 0); if (tinfo->curr.period == spi_period(starget) && tinfo->curr.width == spi_width(starget) @@ -1639,6 +1643,10 @@ ahd_send_async(struct ahd_softc *ahd, char channel, spi_dt(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_DT_REQ ? 1 : 0; spi_qas(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_QAS_REQ ? 1 : 0; spi_iu(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ ? 1 : 0; + spi_rd_strm(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_RD_STRM ? 1 : 0; + spi_pcomp_en(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_PCOMP_EN ? 1 : 0; + spi_rti(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_RTI ? 1 : 0; + spi_wr_flow(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_WR_FLOW ? 1 : 0; spi_display_xfer_agreement(starget); break; } @@ -2318,18 +2326,6 @@ ahd_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) static void ahd_linux_exit(void); -static void ahd_linux_set_xferflags(struct scsi_target *starget, unsigned int ppr_options, unsigned int period) -{ - spi_qas(starget) = (ppr_options & MSG_EXT_PPR_QAS_REQ)? 1 : 0; - spi_dt(starget) = (ppr_options & MSG_EXT_PPR_DT_REQ)? 1 : 0; - spi_iu(starget) = (ppr_options & MSG_EXT_PPR_IU_REQ) ? 1 : 0; - spi_rd_strm(starget) = (ppr_options & MSG_EXT_PPR_RD_STRM) ? 1 : 0; - spi_wr_flow(starget) = (ppr_options & MSG_EXT_PPR_WR_FLOW) ? 1 : 0; - spi_pcomp_en(starget) = (ppr_options & MSG_EXT_PPR_PCOMP_EN) ? 1 : 0; - spi_rti(starget) = (ppr_options & MSG_EXT_PPR_RTI) ? 1 : 0; - spi_period(starget) = period; -} - static void ahd_linux_set_width(struct scsi_target *starget, int width) { struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); @@ -2388,8 +2384,6 @@ static void ahd_linux_set_period(struct scsi_target *starget, int period) ahd_find_syncrate(ahd, &period, &ppr_options, dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); - ahd_linux_set_xferflags(starget, ppr_options, period); - ahd_lock(ahd, &flags); ahd_set_syncrate(ahd, &devinfo, period, offset, ppr_options, AHD_TRANS_GOAL, FALSE); @@ -2424,7 +2418,6 @@ static void ahd_linux_set_offset(struct scsi_target *starget, int offset) ahd_find_syncrate(ahd, &period, &ppr_options, dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); } - ahd_linux_set_xferflags(starget, ppr_options, period); ahd_lock(ahd, &flags); ahd_set_syncrate(ahd, &devinfo, period, offset, ppr_options, @@ -2467,8 +2460,6 @@ static void ahd_linux_set_dt(struct scsi_target *starget, int dt) ahd_find_syncrate(ahd, &period, &ppr_options, dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); - ahd_linux_set_xferflags(starget, ppr_options, period); - ahd_lock(ahd, &flags); ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, ppr_options, AHD_TRANS_GOAL, FALSE); @@ -2508,8 +2499,6 @@ static void ahd_linux_set_qas(struct scsi_target *starget, int qas) ahd_find_syncrate(ahd, &period, &ppr_options, dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); - spi_qas(starget) = (ppr_options & MSG_EXT_PPR_QAS_REQ)? 1 : 0; - ahd_lock(ahd, &flags); ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, ppr_options, AHD_TRANS_GOAL, FALSE); @@ -2550,8 +2539,6 @@ static void ahd_linux_set_iu(struct scsi_target *starget, int iu) ahd_find_syncrate(ahd, &period, &ppr_options, dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); - ahd_linux_set_xferflags(starget, ppr_options, period); - ahd_lock(ahd, &flags); ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, ppr_options, AHD_TRANS_GOAL, FALSE); @@ -2588,8 +2575,6 @@ static void ahd_linux_set_rd_strm(struct scsi_target *starget, int rdstrm) ahd_find_syncrate(ahd, &period, &ppr_options, dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); - spi_rd_strm(starget) = (ppr_options & MSG_EXT_PPR_RD_STRM) ? 1 : 0; - ahd_lock(ahd, &flags); ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, ppr_options, AHD_TRANS_GOAL, FALSE); @@ -2626,8 +2611,6 @@ static void ahd_linux_set_wr_flow(struct scsi_target *starget, int wrflow) ahd_find_syncrate(ahd, &period, &ppr_options, dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); - spi_wr_flow(starget) = (ppr_options & MSG_EXT_PPR_WR_FLOW) ? 1 : 0; - ahd_lock(ahd, &flags); ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, ppr_options, AHD_TRANS_GOAL, FALSE); @@ -2672,8 +2655,6 @@ static void ahd_linux_set_rti(struct scsi_target *starget, int rti) ahd_find_syncrate(ahd, &period, &ppr_options, dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); - spi_rti(starget) = (ppr_options & MSG_EXT_PPR_RTI) ? 1 : 0; - ahd_lock(ahd, &flags); ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, ppr_options, AHD_TRANS_GOAL, FALSE); @@ -2710,8 +2691,6 @@ static void ahd_linux_set_pcomp_en(struct scsi_target *starget, int pcomp) ahd_find_syncrate(ahd, &period, &ppr_options, dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); - spi_pcomp_en(starget) = (ppr_options & MSG_EXT_PPR_PCOMP_EN) ? 1 : 0; - ahd_lock(ahd, &flags); ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, ppr_options, AHD_TRANS_GOAL, FALSE); diff --git a/drivers/scsi/aic7xxx/aic79xx_proc.c b/drivers/scsi/aic7xxx/aic79xx_proc.c index 2058aa9b5c80..cffdd104f9e4 100644 --- a/drivers/scsi/aic7xxx/aic79xx_proc.c +++ b/drivers/scsi/aic7xxx/aic79xx_proc.c @@ -178,9 +178,9 @@ ahd_dump_target_state(struct ahd_softc *ahd, struct info_str *info, copy_info(info, "\tUser: "); ahd_format_transinfo(info, &tinfo->user); starget = ahd->platform_data->starget[target_offset]; - targ = scsi_transport_target_data(starget); - if (targ == NULL) + if (starget == NULL) return; + targ = scsi_transport_target_data(starget); copy_info(info, "\tGoal: "); ahd_format_transinfo(info, &tinfo->goal); From d872ebe4549576e7aab60ed7c746193196381dd0 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Wed, 3 Aug 2005 15:43:52 -0500 Subject: [PATCH 028/114] [SCSI] add missing hold_mcs parameter to the spi transport class This parameter is important only to people who take the time to tune the margin control settings, otherwise it's completely irrelevant. However, just in case anyone should want to do this, it's appropriate to include the parameter. I don't do anything with it in DV by design, so the parameter will come up as off by default, so if anyone actually wants to play with the margin control settings they'll have to enable it under the spi_transport class first. I also updated the transfer settings display to report all of the PPR settings instead of only DT, IU and QAS Signed-off-by: James Bottomley --- drivers/scsi/scsi_transport_spi.c | 20 +++++++++++++++----- include/scsi/scsi_transport_spi.h | 5 +++++ 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c index 7670919a087a..e7b9570c818b 100644 --- a/drivers/scsi/scsi_transport_spi.c +++ b/drivers/scsi/scsi_transport_spi.c @@ -35,7 +35,7 @@ #define SPI_PRINTK(x, l, f, a...) dev_printk(l, &(x)->dev, f , ##a) -#define SPI_NUM_ATTRS 13 /* increase this if you add attributes */ +#define SPI_NUM_ATTRS 14 /* increase this if you add attributes */ #define SPI_OTHER_ATTRS 1 /* Increase this if you add "always * on" attributes */ #define SPI_HOST_ATTRS 1 @@ -231,6 +231,7 @@ static int spi_setup_transport_attrs(struct device *dev) spi_rd_strm(starget) = 0; spi_rti(starget) = 0; spi_pcomp_en(starget) = 0; + spi_hold_mcs(starget) = 0; spi_dv_pending(starget) = 0; spi_initial_dv(starget) = 0; init_MUTEX(&spi_dv_sem(starget)); @@ -347,6 +348,7 @@ spi_transport_rd_attr(wr_flow, "%d\n"); spi_transport_rd_attr(rd_strm, "%d\n"); spi_transport_rd_attr(rti, "%d\n"); spi_transport_rd_attr(pcomp_en, "%d\n"); +spi_transport_rd_attr(hold_mcs, "%d\n"); /* we only care about the first child device so we return 1 */ static int child_iter(struct device *dev, void *data) @@ -1028,10 +1030,17 @@ void spi_display_xfer_agreement(struct scsi_target *starget) sprint_frac(tmp, picosec, 1000); dev_info(&starget->dev, - "%s %sSCSI %d.%d MB/s %s%s%s (%s ns, offset %d)\n", - scsi, tp->width ? "WIDE " : "", kb100/10, kb100 % 10, - tp->dt ? "DT" : "ST", tp->iu ? " IU" : "", - tp->qas ? " QAS" : "", tmp, tp->offset); + "%s %sSCSI %d.%d MB/s %s%s%s%s%s%s%s%s (%s ns, offset %d)\n", + scsi, tp->width ? "WIDE " : "", kb100/10, kb100 % 10, + tp->dt ? "DT" : "ST", + tp->iu ? " IU" : "", + tp->qas ? " QAS" : "", + tp->rd_strm ? " RDSTRM" : "", + tp->rti ? " RTI" : "", + tp->wr_flow ? " WRFLOW" : "", + tp->pcomp_en ? " PCOMP" : "", + tp->hold_mcs ? " HMCS" : "", + tmp, tp->offset); } else { dev_info(&starget->dev, "%sasynchronous.\n", tp->width ? "wide " : ""); @@ -1154,6 +1163,7 @@ spi_attach_transport(struct spi_function_template *ft) SETUP_ATTRIBUTE(rd_strm); SETUP_ATTRIBUTE(rti); SETUP_ATTRIBUTE(pcomp_en); + SETUP_ATTRIBUTE(hold_mcs); /* if you add an attribute but forget to increase SPI_NUM_ATTRS * this bug will trigger */ diff --git a/include/scsi/scsi_transport_spi.h b/include/scsi/scsi_transport_spi.h index a30d6cd4c0e8..d8ef86006e02 100644 --- a/include/scsi/scsi_transport_spi.h +++ b/include/scsi/scsi_transport_spi.h @@ -39,6 +39,7 @@ struct spi_transport_attrs { unsigned int rd_strm:1; /* Read streaming enabled */ unsigned int rti:1; /* Retain Training Information */ unsigned int pcomp_en:1;/* Precompensation enabled */ + unsigned int hold_mcs:1;/* Hold Margin Control Settings */ unsigned int initial_dv:1; /* DV done to this target yet */ unsigned long flags; /* flags field for drivers to use */ /* Device Properties fields */ @@ -78,6 +79,7 @@ struct spi_host_attrs { #define spi_rd_strm(x) (((struct spi_transport_attrs *)&(x)->starget_data)->rd_strm) #define spi_rti(x) (((struct spi_transport_attrs *)&(x)->starget_data)->rti) #define spi_pcomp_en(x) (((struct spi_transport_attrs *)&(x)->starget_data)->pcomp_en) +#define spi_hold_mcs(x) (((struct spi_transport_attrs *)&(x)->starget_data)->hold_mcs) #define spi_initial_dv(x) (((struct spi_transport_attrs *)&(x)->starget_data)->initial_dv) #define spi_support_sync(x) (((struct spi_transport_attrs *)&(x)->starget_data)->support_sync) @@ -114,6 +116,8 @@ struct spi_function_template { void (*set_rti)(struct scsi_target *, int); void (*get_pcomp_en)(struct scsi_target *); void (*set_pcomp_en)(struct scsi_target *, int); + void (*get_hold_mcs)(struct scsi_target *); + void (*set_hold_mcs)(struct scsi_target *, int); void (*get_signalling)(struct Scsi_Host *); void (*set_signalling)(struct Scsi_Host *, enum spi_signal_type); /* The driver sets these to tell the transport class it @@ -130,6 +134,7 @@ struct spi_function_template { unsigned long show_rd_strm:1; unsigned long show_rti:1; unsigned long show_pcomp_en:1; + unsigned long show_hold_mcs:1; }; struct scsi_transport_template *spi_attach_transport(struct spi_function_template *); From 88ff29a4a5a8c4e0ecf375f783be071d1e7e264d Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Wed, 3 Aug 2005 15:59:04 -0500 Subject: [PATCH 029/114] [SCSI] aic79xx: add hold_mcs to the transport parameters since this card can support the setting, add it to the parameter list. Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic79xx_osm.c | 38 +++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index 10a2570ca387..982a74a145f7 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -1628,7 +1628,8 @@ ahd_send_async(struct ahd_softc *ahd, char channel, + (spi_rd_strm(starget) ? MSG_EXT_PPR_RD_STRM : 0) + (spi_pcomp_en(starget) ? MSG_EXT_PPR_PCOMP_EN : 0) + (spi_rti(starget) ? MSG_EXT_PPR_RTI : 0) - + (spi_wr_flow(starget) ? MSG_EXT_PPR_WR_FLOW : 0); + + (spi_wr_flow(starget) ? MSG_EXT_PPR_WR_FLOW : 0) + + (spi_hold_mcs(starget) ? MSG_EXT_PPR_HOLD_MCS : 0); if (tinfo->curr.period == spi_period(starget) && tinfo->curr.width == spi_width(starget) @@ -1647,6 +1648,7 @@ ahd_send_async(struct ahd_softc *ahd, char channel, spi_pcomp_en(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_PCOMP_EN ? 1 : 0; spi_rti(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_RTI ? 1 : 0; spi_wr_flow(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_WR_FLOW ? 1 : 0; + spi_hold_mcs(starget) = tinfo->curr.ppr_options & MSG_EXT_PPR_HOLD_MCS ? 1 : 0; spi_display_xfer_agreement(starget); break; } @@ -2697,6 +2699,38 @@ static void ahd_linux_set_pcomp_en(struct scsi_target *starget, int pcomp) ahd_unlock(ahd, &flags); } +static void ahd_linux_set_hold_mcs(struct scsi_target *starget, int hold) +{ + struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); + struct ahd_softc *ahd = *((struct ahd_softc **)shost->hostdata); + struct ahd_tmode_tstate *tstate; + struct ahd_initiator_tinfo *tinfo + = ahd_fetch_transinfo(ahd, + starget->channel + 'A', + shost->this_id, starget->id, &tstate); + struct ahd_devinfo devinfo; + unsigned int ppr_options = tinfo->goal.ppr_options + & ~MSG_EXT_PPR_HOLD_MCS; + unsigned int period = tinfo->goal.period; + unsigned int dt = ppr_options & MSG_EXT_PPR_DT_REQ; + unsigned long flags; + + if (hold) + ppr_options |= MSG_EXT_PPR_HOLD_MCS; + + ahd_compile_devinfo(&devinfo, shost->this_id, starget->id, 0, + starget->channel + 'A', ROLE_INITIATOR); + ahd_find_syncrate(ahd, &period, &ppr_options, + dt ? AHD_SYNCRATE_MAX : AHD_SYNCRATE_ULTRA2); + + ahd_lock(ahd, &flags); + ahd_set_syncrate(ahd, &devinfo, period, tinfo->goal.offset, + ppr_options, AHD_TRANS_GOAL, FALSE); + ahd_unlock(ahd, &flags); +} + + + static struct spi_function_template ahd_linux_transport_functions = { .set_offset = ahd_linux_set_offset, .show_offset = 1, @@ -2718,6 +2752,8 @@ static struct spi_function_template ahd_linux_transport_functions = { .show_rti = 1, .set_pcomp_en = ahd_linux_set_pcomp_en, .show_pcomp_en = 1, + .set_hold_mcs = ahd_linux_set_hold_mcs, + .show_hold_mcs = 1, }; From 52b5cfb355b2b3274979d25490f190d478ab1fad Mon Sep 17 00:00:00 2001 From: Hannes Reinecke Date: Thu, 4 Aug 2005 09:16:59 +0200 Subject: [PATCH 030/114] [SCSI] aic79xx: fixup DT setting this patch is just a cross-port of the fixup for aic7xxx DT settings. As the same restrictions apply for aic79xx also (DT requires wide transfers) the dt setting routine should be modified equivalently. And an invalid period setting will be caught by ahd_find_syncrate() anyway. Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic79xx_osm.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index 982a74a145f7..40f32bb23972 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -2440,6 +2440,7 @@ static void ahd_linux_set_dt(struct scsi_target *starget, int dt) unsigned int ppr_options = tinfo->goal.ppr_options & ~MSG_EXT_PPR_DT_REQ; unsigned int period = tinfo->goal.period; + unsigned int width = tinfo->goal.width; unsigned long flags; #ifdef AHD_DEBUG @@ -2449,8 +2450,8 @@ static void ahd_linux_set_dt(struct scsi_target *starget, int dt) #endif if (dt) { ppr_options |= MSG_EXT_PPR_DT_REQ; - if (period > 9) - period = 9; /* at least 12.5ns for DT */ + if (!width) + ahd_linux_set_width(starget, 1); } else { if (period <= 9) period = 10; /* If resetting DT, period must be >= 25ns */ From 79778a27be4c704552a18cf2a3e8b9e30623acd1 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Thu, 4 Aug 2005 17:33:22 -0500 Subject: [PATCH 031/114] [SCSI] aic7xxx: upport all sequencer and core fixes from adaptec version 6.3.9 This patch upports all relevant code fixes and bumps the driver version to 7.0 to signify starting a new tree. Signed-off-by: James Bottomley --- Documentation/scsi/aic7xxx.txt | 6 +- drivers/scsi/aic7xxx/aic7xxx.h | 4 +- drivers/scsi/aic7xxx/aic7xxx.reg | 4 +- drivers/scsi/aic7xxx/aic7xxx.seq | 5 +- drivers/scsi/aic7xxx/aic7xxx_93cx6.c | 36 +- drivers/scsi/aic7xxx/aic7xxx_core.c | 60 +- drivers/scsi/aic7xxx/aic7xxx_osm.c | 2 + drivers/scsi/aic7xxx/aic7xxx_osm.h | 2 +- drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped | 6 +- .../scsi/aic7xxx/aic7xxx_reg_print.c_shipped | 4 +- drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped | 933 +++++++++--------- 11 files changed, 549 insertions(+), 513 deletions(-) diff --git a/Documentation/scsi/aic7xxx.txt b/Documentation/scsi/aic7xxx.txt index 160e7354cd1e..47e74ddc4bc9 100644 --- a/Documentation/scsi/aic7xxx.txt +++ b/Documentation/scsi/aic7xxx.txt @@ -1,5 +1,5 @@ ==================================================================== -= Adaptec Aic7xxx Fast -> Ultra160 Family Manager Set v6.2.28 = += Adaptec Aic7xxx Fast -> Ultra160 Family Manager Set v7.0 = = README for = = The Linux Operating System = ==================================================================== @@ -131,6 +131,10 @@ The following information is available in this file: SCSI "stub" effects. 2. Version History + 7.0 (4th August, 2005) + - Updated driver to use SCSI transport class infrastructure + - Upported sequencer and core fixes from last adaptec released + version of the driver. 6.2.36 (June 3rd, 2003) - Correct code that disables PCI parity error checking. - Correct and simplify handling of the ignore wide residue diff --git a/drivers/scsi/aic7xxx/aic7xxx.h b/drivers/scsi/aic7xxx/aic7xxx.h index 088cbc23743d..91d294c6334e 100644 --- a/drivers/scsi/aic7xxx/aic7xxx.h +++ b/drivers/scsi/aic7xxx/aic7xxx.h @@ -37,7 +37,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.h#79 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.h#85 $ * * $FreeBSD$ */ @@ -243,7 +243,7 @@ typedef enum { */ AHC_AIC7850_FE = AHC_SPIOCAP|AHC_AUTOPAUSE|AHC_TARGETMODE|AHC_ULTRA, AHC_AIC7860_FE = AHC_AIC7850_FE, - AHC_AIC7870_FE = AHC_TARGETMODE, + AHC_AIC7870_FE = AHC_TARGETMODE|AHC_AUTOPAUSE, AHC_AIC7880_FE = AHC_AIC7870_FE|AHC_ULTRA, /* * Although we have space for both the initiator and diff --git a/drivers/scsi/aic7xxx/aic7xxx.reg b/drivers/scsi/aic7xxx/aic7xxx.reg index 810ec700d9fc..e196d83b93c7 100644 --- a/drivers/scsi/aic7xxx/aic7xxx.reg +++ b/drivers/scsi/aic7xxx/aic7xxx.reg @@ -39,7 +39,7 @@ * * $FreeBSD$ */ -VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#39 $" +VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#40 $" /* * This file is processed by the aic7xxx_asm utility for use in assembling @@ -1306,7 +1306,6 @@ scratch_ram { */ MWI_RESIDUAL { size 1 - alias TARG_IMMEDIATE_SCB } /* * SCBID of the next SCB to be started by the controller. @@ -1461,6 +1460,7 @@ scratch_ram { */ LAST_MSG { size 1 + alias TARG_IMMEDIATE_SCB } /* diff --git a/drivers/scsi/aic7xxx/aic7xxx.seq b/drivers/scsi/aic7xxx/aic7xxx.seq index d84b741fbab5..15196390e28d 100644 --- a/drivers/scsi/aic7xxx/aic7xxx.seq +++ b/drivers/scsi/aic7xxx/aic7xxx.seq @@ -40,7 +40,7 @@ * $FreeBSD$ */ -VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#56 $" +VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#58 $" PATCH_ARG_LIST = "struct ahc_softc *ahc" PREFIX = "ahc_" @@ -679,6 +679,7 @@ await_busfree: clr SCSIBUSL; /* Prevent bit leakage durint SELTO */ } and SXFRCTL0, ~SPIOEN; + mvi SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT; test SSTAT1,REQINIT|BUSFREE jz .; test SSTAT1, BUSFREE jnz poll_for_work; mvi MISSED_BUSFREE call set_seqint; @@ -1097,7 +1098,7 @@ ultra2_dmahalt: test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz dma_mid_sg; if ((ahc->flags & AHC_TARGETROLE) != 0) { test SSTAT0, TARGET jz dma_last_sg; - if ((ahc->flags & AHC_TMODE_WIDEODD_BUG) != 0) { + if ((ahc->bugs & AHC_TMODE_WIDEODD_BUG) != 0) { test DMAPARAMS, DIRECTION jz dma_mid_sg; } } diff --git a/drivers/scsi/aic7xxx/aic7xxx_93cx6.c b/drivers/scsi/aic7xxx/aic7xxx_93cx6.c index 468d612a44f6..3cb07e114e89 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_93cx6.c +++ b/drivers/scsi/aic7xxx/aic7xxx_93cx6.c @@ -28,9 +28,7 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_93cx6.c#17 $ - * - * $FreeBSD$ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_93cx6.c#19 $ */ /* @@ -64,7 +62,6 @@ * is preceded by an initial zero (leading 0, followed by 16-bits, MSB * first). The clock cycling from low to high initiates the next data * bit to be sent from the chip. - * */ #ifdef __linux__ @@ -81,14 +78,22 @@ * Right now, we only have to read the SEEPROM. But we make it easier to * add other 93Cx6 functions. */ -static struct seeprom_cmd { +struct seeprom_cmd { uint8_t len; - uint8_t bits[9]; -} seeprom_read = {3, {1, 1, 0}}; + uint8_t bits[11]; +}; +/* Short opcodes for the c46 */ static struct seeprom_cmd seeprom_ewen = {9, {1, 0, 0, 1, 1, 0, 0, 0, 0}}; static struct seeprom_cmd seeprom_ewds = {9, {1, 0, 0, 0, 0, 0, 0, 0, 0}}; + +/* Long opcodes for the C56/C66 */ +static struct seeprom_cmd seeprom_long_ewen = {11, {1, 0, 0, 1, 1, 0, 0, 0, 0}}; +static struct seeprom_cmd seeprom_long_ewds = {11, {1, 0, 0, 0, 0, 0, 0, 0, 0}}; + +/* Common opcodes */ static struct seeprom_cmd seeprom_write = {3, {1, 0, 1}}; +static struct seeprom_cmd seeprom_read = {3, {1, 1, 0}}; /* * Wait for the SEERDY to go high; about 800 ns. @@ -222,12 +227,25 @@ int ahc_write_seeprom(struct seeprom_descriptor *sd, uint16_t *buf, u_int start_addr, u_int count) { + struct seeprom_cmd *ewen, *ewds; uint16_t v; uint8_t temp; int i, k; /* Place the chip into write-enable mode */ - send_seeprom_cmd(sd, &seeprom_ewen); + if (sd->sd_chip == C46) { + ewen = &seeprom_ewen; + ewds = &seeprom_ewds; + } else if (sd->sd_chip == C56_66) { + ewen = &seeprom_long_ewen; + ewds = &seeprom_long_ewds; + } else { + printf("ahc_write_seeprom: unsupported seeprom type %d\n", + sd->sd_chip); + return (0); + } + + send_seeprom_cmd(sd, ewen); reset_seeprom(sd); /* Write all requested data out to the seeprom. */ @@ -277,7 +295,7 @@ ahc_write_seeprom(struct seeprom_descriptor *sd, uint16_t *buf, } /* Put the chip back into write-protect mode */ - send_seeprom_cmd(sd, &seeprom_ewds); + send_seeprom_cmd(sd, ewds); reset_seeprom(sd); return (1); diff --git a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c index 7bc01e41bcce..58ac46103eb6 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_core.c +++ b/drivers/scsi/aic7xxx/aic7xxx_core.c @@ -37,9 +37,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.c#134 $ - * - * $FreeBSD$ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.c#155 $ */ #ifdef __linux__ @@ -287,10 +285,19 @@ ahc_restart(struct ahc_softc *ahc) ahc_outb(ahc, SEQ_FLAGS2, ahc_inb(ahc, SEQ_FLAGS2) & ~SCB_DMA); } + + /* + * Clear any pending sequencer interrupt. It is no + * longer relevant since we're resetting the Program + * Counter. + */ + ahc_outb(ahc, CLRINT, CLRSEQINT); + ahc_outb(ahc, MWI_RESIDUAL, 0); ahc_outb(ahc, SEQCTL, ahc->seqctl); ahc_outb(ahc, SEQADDR0, 0); ahc_outb(ahc, SEQADDR1, 0); + ahc_unpause(ahc); } @@ -1174,19 +1181,20 @@ ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat) scb_index); } #endif - /* - * Force a renegotiation with this target just in - * case the cable was pulled and will later be - * re-attached. The target may forget its negotiation - * settings with us should it attempt to reselect - * during the interruption. The target will not issue - * a unit attention in this case, so we must always - * renegotiate. - */ ahc_scb_devinfo(ahc, &devinfo, scb); - ahc_force_renegotiation(ahc, &devinfo); ahc_set_transaction_status(scb, CAM_SEL_TIMEOUT); ahc_freeze_devq(ahc, scb); + + /* + * Cancel any pending transactions on the device + * now that it seems to be missing. This will + * also revert us to async/narrow transfers until + * we can renegotiate with the device. + */ + ahc_handle_devreset(ahc, &devinfo, + CAM_SEL_TIMEOUT, + "Selection Timeout", + /*verbose_level*/1); } ahc_outb(ahc, CLRINT, CLRSCSIINT); ahc_restart(ahc); @@ -3763,8 +3771,9 @@ ahc_handle_devreset(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, /*period*/0, /*offset*/0, /*ppr_options*/0, AHC_TRANS_CUR, /*paused*/TRUE); - ahc_send_async(ahc, devinfo->channel, devinfo->target, - CAM_LUN_WILDCARD, AC_SENT_BDR, NULL); + if (status != CAM_SEL_TIMEOUT) + ahc_send_async(ahc, devinfo->channel, devinfo->target, + CAM_LUN_WILDCARD, AC_SENT_BDR, NULL); if (message != NULL && (verbose_level <= bootverbose)) @@ -4003,14 +4012,6 @@ ahc_reset(struct ahc_softc *ahc, int reinit) * to disturb the integrity of the bus. */ ahc_pause(ahc); - if ((ahc_inb(ahc, HCNTRL) & CHIPRST) != 0) { - /* - * The chip has not been initialized since - * PCI/EISA/VLB bus reset. Don't trust - * "left over BIOS data". - */ - ahc->flags |= AHC_NO_BIOS_INIT; - } sxfrctl1_b = 0; if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7770) { u_int sblkctl; @@ -5036,14 +5037,23 @@ ahc_pause_and_flushwork(struct ahc_softc *ahc) ahc->flags |= AHC_ALL_INTERRUPTS; paused = FALSE; do { - if (paused) + if (paused) { ahc_unpause(ahc); + /* + * Give the sequencer some time to service + * any active selections. + */ + ahc_delay(500); + } ahc_intr(ahc); ahc_pause(ahc); paused = TRUE; ahc_outb(ahc, SCSISEQ, ahc_inb(ahc, SCSISEQ) & ~ENSELO); - ahc_clear_critical_section(ahc); intstat = ahc_inb(ahc, INTSTAT); + if ((intstat & INT_PEND) == 0) { + ahc_clear_critical_section(ahc); + intstat = ahc_inb(ahc, INTSTAT); + } } while (--maxloops && (intstat != 0xFF || (ahc->features & AHC_REMOVABLE) == 0) && ((intstat & INT_PEND) != 0 diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index 116d0f51ca2c..e39361ac6a44 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -635,6 +635,8 @@ ahc_linux_slave_alloc(struct scsi_device *sdev) targ->sdev[sdev->lun] = sdev; + spi_period(starget) = 0; + return 0; } diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h index 0e47ac217549..c52996269240 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.h +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h @@ -265,7 +265,7 @@ ahc_scb_timer_reset(struct scb *scb, u_int usec) /***************************** SMP support ************************************/ #include -#define AIC7XXX_DRIVER_VERSION "6.2.36" +#define AIC7XXX_DRIVER_VERSION "7.0" /*************************** Device Data Structures ***************************/ /* diff --git a/drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped b/drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped index 7c1390ed1179..2ce1febca207 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped +++ b/drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped @@ -2,8 +2,8 @@ * DO NOT EDIT - This file is automatically generated * from the following source files: * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#56 $ - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#39 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#58 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#40 $ */ typedef int (ahc_reg_print_t)(u_int, u_int *, u_int); typedef struct ahc_reg_parse_entry { @@ -1298,7 +1298,6 @@ ahc_reg_print_t ahc_sg_cache_pre_print; #define CMDSIZE_TABLE_TAIL 0x34 #define MWI_RESIDUAL 0x38 -#define TARG_IMMEDIATE_SCB 0x38 #define NEXT_QUEUED_SCB 0x39 @@ -1380,6 +1379,7 @@ ahc_reg_print_t ahc_sg_cache_pre_print; #define RETURN_2 0x52 #define LAST_MSG 0x53 +#define TARG_IMMEDIATE_SCB 0x53 #define SCSISEQ_TEMPLATE 0x54 #define ENSELO 0x40 diff --git a/drivers/scsi/aic7xxx/aic7xxx_reg_print.c_shipped b/drivers/scsi/aic7xxx/aic7xxx_reg_print.c_shipped index 9c713775d44a..88bfd767c51c 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_reg_print.c_shipped +++ b/drivers/scsi/aic7xxx/aic7xxx_reg_print.c_shipped @@ -2,8 +2,8 @@ * DO NOT EDIT - This file is automatically generated * from the following source files: * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#56 $ - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#39 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#58 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#40 $ */ #include "aic7xxx_osm.h" diff --git a/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped b/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped index cf411368a871..4cee08521e75 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped +++ b/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped @@ -2,13 +2,13 @@ * DO NOT EDIT - This file is automatically generated * from the following source files: * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#56 $ - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#39 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#58 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#40 $ */ static uint8_t seqprog[] = { 0xb2, 0x00, 0x00, 0x08, 0xf7, 0x11, 0x22, 0x08, - 0x00, 0x65, 0xec, 0x59, + 0x00, 0x65, 0xee, 0x59, 0xf7, 0x01, 0x02, 0x08, 0xff, 0x6a, 0x24, 0x08, 0x40, 0x00, 0x40, 0x68, @@ -21,15 +21,15 @@ static uint8_t seqprog[] = { 0x01, 0x4d, 0xc8, 0x30, 0x00, 0x4c, 0x12, 0x70, 0x01, 0x39, 0xa2, 0x30, - 0x00, 0x6a, 0xc0, 0x5e, + 0x00, 0x6a, 0xc2, 0x5e, 0x01, 0x51, 0x20, 0x31, 0x01, 0x57, 0xae, 0x00, 0x0d, 0x6a, 0x76, 0x00, - 0x00, 0x51, 0x12, 0x5e, + 0x00, 0x51, 0x14, 0x5e, 0x01, 0x51, 0xc8, 0x30, 0x00, 0x39, 0xc8, 0x60, 0x00, 0xbb, 0x30, 0x70, - 0xc1, 0x6a, 0xd8, 0x5e, + 0xc1, 0x6a, 0xda, 0x5e, 0x01, 0xbf, 0x72, 0x30, 0x01, 0x40, 0x7e, 0x31, 0x01, 0x90, 0x80, 0x30, @@ -49,10 +49,10 @@ static uint8_t seqprog[] = { 0x08, 0x6a, 0x78, 0x00, 0x01, 0x50, 0xc8, 0x30, 0xe0, 0x6a, 0xcc, 0x00, - 0x48, 0x6a, 0xfc, 0x5d, + 0x48, 0x6a, 0xfe, 0x5d, 0x01, 0x6a, 0xdc, 0x01, 0x88, 0x6a, 0xcc, 0x00, - 0x48, 0x6a, 0xfc, 0x5d, + 0x48, 0x6a, 0xfe, 0x5d, 0x01, 0x6a, 0x26, 0x01, 0xf0, 0x19, 0x7a, 0x08, 0x0f, 0x18, 0xc8, 0x08, @@ -93,7 +93,7 @@ static uint8_t seqprog[] = { 0x00, 0x65, 0x20, 0x41, 0x02, 0x57, 0xae, 0x00, 0x00, 0x65, 0x9e, 0x40, - 0x61, 0x6a, 0xd8, 0x5e, + 0x61, 0x6a, 0xda, 0x5e, 0x08, 0x51, 0x20, 0x71, 0x02, 0x0b, 0xb2, 0x78, 0x00, 0x65, 0xae, 0x40, @@ -106,7 +106,7 @@ static uint8_t seqprog[] = { 0x80, 0x3d, 0x7a, 0x00, 0x20, 0x6a, 0x16, 0x00, 0x00, 0x65, 0xcc, 0x41, - 0x00, 0x65, 0xb2, 0x5e, + 0x00, 0x65, 0xb4, 0x5e, 0x00, 0x65, 0x12, 0x40, 0x20, 0x11, 0xd2, 0x68, 0x20, 0x6a, 0x18, 0x00, @@ -140,27 +140,27 @@ static uint8_t seqprog[] = { 0x80, 0x0b, 0xc4, 0x79, 0x12, 0x01, 0x02, 0x00, 0x01, 0xab, 0xac, 0x30, - 0xe4, 0x6a, 0x6e, 0x5d, + 0xe4, 0x6a, 0x70, 0x5d, 0x40, 0x6a, 0x16, 0x00, - 0x80, 0x3e, 0x84, 0x5d, + 0x80, 0x3e, 0x86, 0x5d, 0x20, 0xb8, 0x18, 0x79, - 0x20, 0x6a, 0x84, 0x5d, - 0x00, 0xab, 0x84, 0x5d, + 0x20, 0x6a, 0x86, 0x5d, + 0x00, 0xab, 0x86, 0x5d, 0x01, 0xa9, 0x78, 0x30, 0x10, 0xb8, 0x20, 0x79, - 0xe4, 0x6a, 0x6e, 0x5d, + 0xe4, 0x6a, 0x70, 0x5d, 0x00, 0x65, 0xae, 0x40, 0x10, 0x03, 0x3c, 0x69, 0x08, 0x3c, 0x5a, 0x69, 0x04, 0x3c, 0x92, 0x69, 0x02, 0x3c, 0x98, 0x69, 0x01, 0x3c, 0x44, 0x79, - 0xff, 0x6a, 0x70, 0x00, + 0xff, 0x6a, 0xa6, 0x00, 0x00, 0x65, 0xa4, 0x59, - 0x00, 0x6a, 0xc0, 0x5e, - 0xff, 0x38, 0x30, 0x71, + 0x00, 0x6a, 0xc2, 0x5e, + 0xff, 0x53, 0x30, 0x71, 0x0d, 0x6a, 0x76, 0x00, - 0x00, 0x38, 0x12, 0x5e, + 0x00, 0x53, 0x14, 0x5e, 0x00, 0x65, 0xea, 0x58, 0x12, 0x01, 0x02, 0x00, 0x00, 0x65, 0x18, 0x41, @@ -168,10 +168,10 @@ static uint8_t seqprog[] = { 0x00, 0x65, 0xf2, 0x58, 0xfd, 0x57, 0xae, 0x08, 0x00, 0x65, 0xae, 0x40, - 0xe4, 0x6a, 0x6e, 0x5d, + 0xe4, 0x6a, 0x70, 0x5d, 0x20, 0x3c, 0x4a, 0x79, - 0x02, 0x6a, 0x84, 0x5d, - 0x04, 0x6a, 0x84, 0x5d, + 0x02, 0x6a, 0x86, 0x5d, + 0x04, 0x6a, 0x86, 0x5d, 0x01, 0x03, 0x4c, 0x69, 0xf7, 0x11, 0x22, 0x08, 0xff, 0x6a, 0x24, 0x08, @@ -182,13 +182,13 @@ static uint8_t seqprog[] = { 0x80, 0x86, 0xc8, 0x08, 0x01, 0x4f, 0xc8, 0x30, 0x00, 0x50, 0x6c, 0x61, - 0xc4, 0x6a, 0x6e, 0x5d, + 0xc4, 0x6a, 0x70, 0x5d, 0x40, 0x3c, 0x68, 0x79, - 0x28, 0x6a, 0x84, 0x5d, + 0x28, 0x6a, 0x86, 0x5d, 0x00, 0x65, 0x4c, 0x41, - 0x08, 0x6a, 0x84, 0x5d, + 0x08, 0x6a, 0x86, 0x5d, 0x00, 0x65, 0x4c, 0x41, - 0x84, 0x6a, 0x6e, 0x5d, + 0x84, 0x6a, 0x70, 0x5d, 0x00, 0x65, 0xf2, 0x58, 0x01, 0x66, 0xc8, 0x30, 0x01, 0x64, 0xd8, 0x31, @@ -208,16 +208,16 @@ static uint8_t seqprog[] = { 0xf7, 0x3c, 0x78, 0x08, 0x00, 0x65, 0x20, 0x41, 0x40, 0xaa, 0x7e, 0x10, - 0x04, 0xaa, 0x6e, 0x5d, - 0x00, 0x65, 0x56, 0x42, - 0xc4, 0x6a, 0x6e, 0x5d, + 0x04, 0xaa, 0x70, 0x5d, + 0x00, 0x65, 0x58, 0x42, + 0xc4, 0x6a, 0x70, 0x5d, 0xc0, 0x6a, 0x7e, 0x00, - 0x00, 0xa8, 0x84, 0x5d, + 0x00, 0xa8, 0x86, 0x5d, 0xe4, 0x6a, 0x06, 0x00, - 0x00, 0x6a, 0x84, 0x5d, + 0x00, 0x6a, 0x86, 0x5d, 0x00, 0x65, 0x4c, 0x41, 0x10, 0x3c, 0xa8, 0x69, - 0x00, 0xbb, 0x8a, 0x44, + 0x00, 0xbb, 0x8c, 0x44, 0x18, 0x6a, 0xda, 0x01, 0x01, 0x69, 0xd8, 0x31, 0x1c, 0x6a, 0xd0, 0x01, @@ -227,31 +227,32 @@ static uint8_t seqprog[] = { 0x01, 0x93, 0x26, 0x01, 0x03, 0x6a, 0x2a, 0x01, 0x01, 0x69, 0x32, 0x31, - 0x1c, 0x6a, 0xe0, 0x5d, + 0x1c, 0x6a, 0xe2, 0x5d, 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0xa8, 0x5e, + 0x00, 0x65, 0xaa, 0x5e, 0x01, 0x50, 0xa0, 0x18, 0x02, 0x6a, 0x22, 0x05, 0x1a, 0x01, 0x02, 0x00, 0x80, 0x6a, 0x74, 0x00, 0x40, 0x6a, 0x78, 0x00, 0x40, 0x6a, 0x16, 0x00, - 0x00, 0x65, 0xd8, 0x5d, + 0x00, 0x65, 0xda, 0x5d, 0x01, 0x3f, 0xc8, 0x30, - 0xbf, 0x64, 0x56, 0x7a, - 0x80, 0x64, 0x9e, 0x73, - 0xa0, 0x64, 0x00, 0x74, - 0xc0, 0x64, 0xf4, 0x73, - 0xe0, 0x64, 0x30, 0x74, - 0x01, 0x6a, 0xd8, 0x5e, + 0xbf, 0x64, 0x58, 0x7a, + 0x80, 0x64, 0xa0, 0x73, + 0xa0, 0x64, 0x02, 0x74, + 0xc0, 0x64, 0xf6, 0x73, + 0xe0, 0x64, 0x32, 0x74, + 0x01, 0x6a, 0xda, 0x5e, 0x00, 0x65, 0xcc, 0x41, 0xf7, 0x11, 0x22, 0x08, 0x01, 0x06, 0xd4, 0x30, 0xff, 0x6a, 0x24, 0x08, 0xf7, 0x01, 0x02, 0x08, - 0x09, 0x0c, 0xe6, 0x79, + 0xc0, 0x6a, 0x78, 0x00, + 0x09, 0x0c, 0xe8, 0x79, 0x08, 0x0c, 0x04, 0x68, - 0xb1, 0x6a, 0xd8, 0x5e, + 0xb1, 0x6a, 0xda, 0x5e, 0xff, 0x6a, 0x26, 0x09, 0x12, 0x01, 0x02, 0x00, 0x02, 0x6a, 0x08, 0x30, @@ -264,29 +265,29 @@ static uint8_t seqprog[] = { 0x00, 0xa5, 0x4a, 0x21, 0x00, 0xa6, 0x4c, 0x21, 0x00, 0xa7, 0x4e, 0x25, - 0x08, 0xeb, 0xdc, 0x7e, - 0x80, 0xeb, 0x06, 0x7a, + 0x08, 0xeb, 0xde, 0x7e, + 0x80, 0xeb, 0x08, 0x7a, 0xff, 0x6a, 0xd6, 0x09, - 0x08, 0xeb, 0x0a, 0x6a, + 0x08, 0xeb, 0x0c, 0x6a, 0xff, 0x6a, 0xd4, 0x0c, - 0x80, 0xa3, 0xdc, 0x6e, - 0x88, 0xeb, 0x20, 0x72, - 0x08, 0xeb, 0xdc, 0x6e, - 0x04, 0xea, 0x24, 0xe2, - 0x08, 0xee, 0xdc, 0x6e, + 0x80, 0xa3, 0xde, 0x6e, + 0x88, 0xeb, 0x22, 0x72, + 0x08, 0xeb, 0xde, 0x6e, + 0x04, 0xea, 0x26, 0xe2, + 0x08, 0xee, 0xde, 0x6e, 0x04, 0x6a, 0xd0, 0x81, 0x05, 0xa4, 0xc0, 0x89, 0x03, 0xa5, 0xc2, 0x31, 0x09, 0x6a, 0xd6, 0x05, - 0x00, 0x65, 0x08, 0x5a, + 0x00, 0x65, 0x0a, 0x5a, 0x06, 0xa4, 0xd4, 0x89, - 0x80, 0x94, 0xdc, 0x7e, + 0x80, 0x94, 0xde, 0x7e, 0x07, 0xe9, 0x10, 0x31, 0x01, 0xe9, 0x46, 0x31, - 0x00, 0xa3, 0xba, 0x5e, - 0x00, 0x65, 0xfa, 0x59, + 0x00, 0xa3, 0xbc, 0x5e, + 0x00, 0x65, 0xfc, 0x59, 0x01, 0xa4, 0xca, 0x30, - 0x80, 0xa3, 0x34, 0x7a, + 0x80, 0xa3, 0x36, 0x7a, 0x02, 0x65, 0xca, 0x00, 0x01, 0x65, 0xf8, 0x31, 0x80, 0x93, 0x26, 0x01, @@ -294,162 +295,162 @@ static uint8_t seqprog[] = { 0x01, 0x8c, 0xc8, 0x30, 0x00, 0x88, 0xc8, 0x18, 0x02, 0x64, 0xc8, 0x88, - 0xff, 0x64, 0xdc, 0x7e, - 0xff, 0x8d, 0x4a, 0x6a, - 0xff, 0x8e, 0x4a, 0x6a, + 0xff, 0x64, 0xde, 0x7e, + 0xff, 0x8d, 0x4c, 0x6a, + 0xff, 0x8e, 0x4c, 0x6a, 0x03, 0x8c, 0xd4, 0x98, - 0x00, 0x65, 0xdc, 0x56, + 0x00, 0x65, 0xde, 0x56, 0x01, 0x64, 0x70, 0x30, 0xff, 0x64, 0xc8, 0x10, 0x01, 0x64, 0xc8, 0x18, 0x00, 0x8c, 0x18, 0x19, 0xff, 0x8d, 0x1a, 0x21, 0xff, 0x8e, 0x1c, 0x25, - 0xc0, 0x3c, 0x5a, 0x7a, - 0x21, 0x6a, 0xd8, 0x5e, + 0xc0, 0x3c, 0x5c, 0x7a, + 0x21, 0x6a, 0xda, 0x5e, 0xa8, 0x6a, 0x76, 0x00, 0x79, 0x6a, 0x76, 0x00, - 0x40, 0x3f, 0x62, 0x6a, + 0x40, 0x3f, 0x64, 0x6a, 0x04, 0x3b, 0x76, 0x00, 0x04, 0x6a, 0xd4, 0x81, - 0x20, 0x3c, 0x6a, 0x7a, - 0x51, 0x6a, 0xd8, 0x5e, - 0x00, 0x65, 0x82, 0x42, + 0x20, 0x3c, 0x6c, 0x7a, + 0x51, 0x6a, 0xda, 0x5e, + 0x00, 0x65, 0x84, 0x42, 0x20, 0x3c, 0x78, 0x00, - 0x00, 0xb3, 0xba, 0x5e, + 0x00, 0xb3, 0xbc, 0x5e, 0x07, 0xac, 0x10, 0x31, 0x05, 0xb3, 0x46, 0x31, 0x88, 0x6a, 0xcc, 0x00, - 0xac, 0x6a, 0xee, 0x5d, + 0xac, 0x6a, 0xf0, 0x5d, 0xa3, 0x6a, 0xcc, 0x00, - 0xb3, 0x6a, 0xf2, 0x5d, - 0x00, 0x65, 0x3a, 0x5a, + 0xb3, 0x6a, 0xf4, 0x5d, + 0x00, 0x65, 0x3c, 0x5a, 0xfd, 0xa4, 0x48, 0x09, 0x03, 0x8c, 0x10, 0x30, - 0x00, 0x65, 0xe6, 0x5d, - 0x01, 0xa4, 0x94, 0x7a, + 0x00, 0x65, 0xe8, 0x5d, + 0x01, 0xa4, 0x96, 0x7a, 0x04, 0x3b, 0x76, 0x08, 0x01, 0x3b, 0x26, 0x31, 0x80, 0x02, 0x04, 0x00, - 0x10, 0x0c, 0x8a, 0x7a, - 0x03, 0x9e, 0x8c, 0x6a, + 0x10, 0x0c, 0x8c, 0x7a, + 0x03, 0x9e, 0x8e, 0x6a, 0x7f, 0x02, 0x04, 0x08, - 0x91, 0x6a, 0xd8, 0x5e, + 0x91, 0x6a, 0xda, 0x5e, 0x00, 0x65, 0xcc, 0x41, 0x01, 0xa4, 0xca, 0x30, - 0x80, 0xa3, 0x9a, 0x7a, + 0x80, 0xa3, 0x9c, 0x7a, 0x02, 0x65, 0xca, 0x00, 0x01, 0x65, 0xf8, 0x31, 0x01, 0x3b, 0x26, 0x31, - 0x00, 0x65, 0x0e, 0x5a, - 0x01, 0xfc, 0xa8, 0x6a, - 0x80, 0x0b, 0x9e, 0x6a, - 0x10, 0x0c, 0x9e, 0x7a, - 0x20, 0x93, 0x9e, 0x6a, + 0x00, 0x65, 0x10, 0x5a, + 0x01, 0xfc, 0xaa, 0x6a, + 0x80, 0x0b, 0xa0, 0x6a, + 0x10, 0x0c, 0xa0, 0x7a, + 0x20, 0x93, 0xa0, 0x6a, 0x02, 0x93, 0x26, 0x01, - 0x02, 0xfc, 0xb2, 0x7a, - 0x40, 0x0d, 0xc6, 0x6a, + 0x02, 0xfc, 0xb4, 0x7a, + 0x40, 0x0d, 0xc8, 0x6a, 0x01, 0xa4, 0x48, 0x01, - 0x00, 0x65, 0xc6, 0x42, - 0x40, 0x0d, 0xb8, 0x6a, - 0x00, 0x65, 0x0e, 0x5a, - 0x00, 0x65, 0xaa, 0x42, - 0x80, 0xfc, 0xc2, 0x7a, - 0x80, 0xa4, 0xc2, 0x6a, + 0x00, 0x65, 0xc8, 0x42, + 0x40, 0x0d, 0xba, 0x6a, + 0x00, 0x65, 0x10, 0x5a, + 0x00, 0x65, 0xac, 0x42, + 0x80, 0xfc, 0xc4, 0x7a, + 0x80, 0xa4, 0xc4, 0x6a, 0xff, 0xa5, 0x4a, 0x19, 0xff, 0xa6, 0x4c, 0x21, 0xff, 0xa7, 0x4e, 0x21, 0xf8, 0xfc, 0x48, 0x09, 0x7f, 0xa3, 0x46, 0x09, - 0x04, 0x3b, 0xe2, 0x6a, + 0x04, 0x3b, 0xe4, 0x6a, 0x02, 0x93, 0x26, 0x01, - 0x01, 0x94, 0xc8, 0x7a, - 0x01, 0x94, 0xc8, 0x7a, - 0x01, 0x94, 0xc8, 0x7a, - 0x01, 0x94, 0xc8, 0x7a, - 0x01, 0x94, 0xc8, 0x7a, - 0x01, 0xa4, 0xe0, 0x7a, - 0x01, 0xfc, 0xd6, 0x7a, - 0x01, 0x94, 0xe2, 0x6a, - 0x01, 0x94, 0xe2, 0x6a, - 0x01, 0x94, 0xe2, 0x6a, - 0x00, 0x65, 0x82, 0x42, - 0x01, 0x94, 0xe0, 0x7a, - 0x10, 0x94, 0xe2, 0x6a, + 0x01, 0x94, 0xca, 0x7a, + 0x01, 0x94, 0xca, 0x7a, + 0x01, 0x94, 0xca, 0x7a, + 0x01, 0x94, 0xca, 0x7a, + 0x01, 0x94, 0xca, 0x7a, + 0x01, 0xa4, 0xe2, 0x7a, + 0x01, 0xfc, 0xd8, 0x7a, + 0x01, 0x94, 0xe4, 0x6a, + 0x01, 0x94, 0xe4, 0x6a, + 0x01, 0x94, 0xe4, 0x6a, + 0x00, 0x65, 0x84, 0x42, + 0x01, 0x94, 0xe2, 0x7a, + 0x10, 0x94, 0xe4, 0x6a, 0xd7, 0x93, 0x26, 0x09, - 0x28, 0x93, 0xe6, 0x6a, + 0x28, 0x93, 0xe8, 0x6a, 0x01, 0x85, 0x0a, 0x01, - 0x02, 0xfc, 0xee, 0x6a, + 0x02, 0xfc, 0xf0, 0x6a, 0x01, 0x14, 0x46, 0x31, 0xff, 0x6a, 0x10, 0x09, 0xfe, 0x85, 0x0a, 0x09, - 0xff, 0x38, 0xfc, 0x6a, - 0x80, 0xa3, 0xfc, 0x7a, - 0x80, 0x0b, 0xfa, 0x7a, - 0x04, 0x3b, 0xfc, 0x7a, + 0xff, 0x38, 0xfe, 0x6a, + 0x80, 0xa3, 0xfe, 0x7a, + 0x80, 0x0b, 0xfc, 0x7a, + 0x04, 0x3b, 0xfe, 0x7a, 0xbf, 0x3b, 0x76, 0x08, 0x01, 0x3b, 0x26, 0x31, - 0x00, 0x65, 0x0e, 0x5a, - 0x01, 0x0b, 0x0a, 0x6b, - 0x10, 0x0c, 0xfe, 0x7a, - 0x04, 0x93, 0x08, 0x6b, - 0x01, 0x94, 0x06, 0x7b, - 0x10, 0x94, 0x08, 0x6b, + 0x00, 0x65, 0x10, 0x5a, + 0x01, 0x0b, 0x0c, 0x6b, + 0x10, 0x0c, 0x00, 0x7b, + 0x04, 0x93, 0x0a, 0x6b, + 0x01, 0x94, 0x08, 0x7b, + 0x10, 0x94, 0x0a, 0x6b, 0xc7, 0x93, 0x26, 0x09, 0x01, 0x99, 0xd4, 0x30, - 0x38, 0x93, 0x0c, 0x6b, - 0xff, 0x08, 0x5a, 0x6b, - 0xff, 0x09, 0x5a, 0x6b, - 0xff, 0x0a, 0x5a, 0x6b, - 0xff, 0x38, 0x28, 0x7b, + 0x38, 0x93, 0x0e, 0x6b, + 0xff, 0x08, 0x5c, 0x6b, + 0xff, 0x09, 0x5c, 0x6b, + 0xff, 0x0a, 0x5c, 0x6b, + 0xff, 0x38, 0x2a, 0x7b, 0x04, 0x14, 0x10, 0x31, 0x01, 0x38, 0x18, 0x31, 0x02, 0x6a, 0x1a, 0x31, 0x88, 0x6a, 0xcc, 0x00, - 0x14, 0x6a, 0xf4, 0x5d, - 0x00, 0x38, 0xe0, 0x5d, + 0x14, 0x6a, 0xf6, 0x5d, + 0x00, 0x38, 0xe2, 0x5d, 0xff, 0x6a, 0x70, 0x08, - 0x00, 0x65, 0x54, 0x43, - 0x80, 0xa3, 0x2e, 0x7b, + 0x00, 0x65, 0x56, 0x43, + 0x80, 0xa3, 0x30, 0x7b, 0x01, 0xa4, 0x48, 0x01, - 0x00, 0x65, 0x5a, 0x43, - 0x08, 0xeb, 0x34, 0x7b, - 0x00, 0x65, 0x0e, 0x5a, - 0x08, 0xeb, 0x30, 0x6b, + 0x00, 0x65, 0x5c, 0x43, + 0x08, 0xeb, 0x36, 0x7b, + 0x00, 0x65, 0x10, 0x5a, + 0x08, 0xeb, 0x32, 0x6b, 0x07, 0xe9, 0x10, 0x31, 0x01, 0xe9, 0xca, 0x30, 0x01, 0x65, 0x46, 0x31, - 0x00, 0x6a, 0xba, 0x5e, + 0x00, 0x6a, 0xbc, 0x5e, 0x88, 0x6a, 0xcc, 0x00, - 0xa4, 0x6a, 0xf4, 0x5d, - 0x08, 0x6a, 0xe0, 0x5d, + 0xa4, 0x6a, 0xf6, 0x5d, + 0x08, 0x6a, 0xe2, 0x5d, 0x0d, 0x93, 0x26, 0x01, - 0x00, 0x65, 0xa8, 0x5e, + 0x00, 0x65, 0xaa, 0x5e, 0x88, 0x6a, 0xcc, 0x00, - 0x00, 0x65, 0x8a, 0x5e, + 0x00, 0x65, 0x8c, 0x5e, 0x01, 0x99, 0x46, 0x31, - 0x00, 0xa3, 0xba, 0x5e, + 0x00, 0xa3, 0xbc, 0x5e, 0x01, 0x88, 0x10, 0x31, - 0x00, 0x65, 0x3a, 0x5a, - 0x00, 0x65, 0xfa, 0x59, + 0x00, 0x65, 0x3c, 0x5a, + 0x00, 0x65, 0xfc, 0x59, 0x03, 0x8c, 0x10, 0x30, - 0x00, 0x65, 0xe6, 0x5d, - 0x80, 0x0b, 0x82, 0x6a, - 0x80, 0x0b, 0x62, 0x6b, - 0x01, 0x0c, 0x5c, 0x7b, - 0x10, 0x0c, 0x82, 0x7a, - 0x03, 0x9e, 0x82, 0x6a, - 0x00, 0x65, 0x04, 0x5a, - 0x00, 0x6a, 0xba, 0x5e, - 0x01, 0xa4, 0x82, 0x6b, - 0xff, 0x38, 0x78, 0x7b, + 0x00, 0x65, 0xe8, 0x5d, + 0x80, 0x0b, 0x84, 0x6a, + 0x80, 0x0b, 0x64, 0x6b, + 0x01, 0x0c, 0x5e, 0x7b, + 0x10, 0x0c, 0x84, 0x7a, + 0x03, 0x9e, 0x84, 0x6a, + 0x00, 0x65, 0x06, 0x5a, + 0x00, 0x6a, 0xbc, 0x5e, + 0x01, 0xa4, 0x84, 0x6b, + 0xff, 0x38, 0x7a, 0x7b, 0x01, 0x38, 0xc8, 0x30, 0x00, 0x08, 0x40, 0x19, 0xff, 0x6a, 0xc8, 0x08, 0x00, 0x09, 0x42, 0x21, 0x00, 0x0a, 0x44, 0x21, 0xff, 0x6a, 0x70, 0x08, - 0x00, 0x65, 0x7a, 0x43, + 0x00, 0x65, 0x7c, 0x43, 0x03, 0x08, 0x40, 0x31, 0x03, 0x08, 0x40, 0x31, 0x01, 0x08, 0x40, 0x31, @@ -461,16 +462,16 @@ static uint8_t seqprog[] = { 0x04, 0x3c, 0xcc, 0x79, 0xfb, 0x3c, 0x78, 0x08, 0x04, 0x93, 0x20, 0x79, - 0x01, 0x0c, 0x8e, 0x6b, + 0x01, 0x0c, 0x90, 0x6b, 0x80, 0xba, 0x20, 0x79, 0x80, 0x04, 0x20, 0x79, - 0xe4, 0x6a, 0x6e, 0x5d, - 0x23, 0x6a, 0x84, 0x5d, - 0x01, 0x6a, 0x84, 0x5d, + 0xe4, 0x6a, 0x70, 0x5d, + 0x23, 0x6a, 0x86, 0x5d, + 0x01, 0x6a, 0x86, 0x5d, 0x00, 0x65, 0x20, 0x41, 0x00, 0x65, 0xcc, 0x41, - 0x80, 0x3c, 0xa2, 0x7b, - 0x21, 0x6a, 0xd8, 0x5e, + 0x80, 0x3c, 0xa4, 0x7b, + 0x21, 0x6a, 0xda, 0x5e, 0x01, 0xbc, 0x18, 0x31, 0x02, 0x6a, 0x1a, 0x31, 0x02, 0x6a, 0xf8, 0x01, @@ -480,16 +481,16 @@ static uint8_t seqprog[] = { 0xff, 0x6a, 0x12, 0x08, 0xff, 0x6a, 0x14, 0x08, 0xf3, 0xbc, 0xd4, 0x18, - 0xa0, 0x6a, 0xc8, 0x53, + 0xa0, 0x6a, 0xca, 0x53, 0x04, 0xa0, 0x10, 0x31, 0xac, 0x6a, 0x26, 0x01, 0x04, 0xa0, 0x10, 0x31, 0x03, 0x08, 0x18, 0x31, 0x88, 0x6a, 0xcc, 0x00, - 0xa0, 0x6a, 0xf4, 0x5d, - 0x00, 0xbc, 0xe0, 0x5d, + 0xa0, 0x6a, 0xf6, 0x5d, + 0x00, 0xbc, 0xe2, 0x5d, 0x3d, 0x6a, 0x26, 0x01, - 0x00, 0x65, 0xe0, 0x43, + 0x00, 0x65, 0xe2, 0x43, 0xff, 0x6a, 0x10, 0x09, 0xa4, 0x6a, 0x26, 0x01, 0x0c, 0xa0, 0x32, 0x31, @@ -499,128 +500,128 @@ static uint8_t seqprog[] = { 0x36, 0x6a, 0x26, 0x01, 0x02, 0x93, 0x26, 0x01, 0x35, 0x6a, 0x26, 0x01, - 0x00, 0x65, 0x9c, 0x5e, - 0x00, 0x65, 0x9c, 0x5e, + 0x00, 0x65, 0x9e, 0x5e, + 0x00, 0x65, 0x9e, 0x5e, 0x02, 0x93, 0x26, 0x01, 0xbf, 0x3c, 0x78, 0x08, - 0x04, 0x0b, 0xe6, 0x6b, - 0x10, 0x0c, 0xe2, 0x7b, - 0x01, 0x03, 0xe6, 0x6b, - 0x20, 0x93, 0xe8, 0x6b, - 0x04, 0x0b, 0xee, 0x6b, + 0x04, 0x0b, 0xe8, 0x6b, + 0x10, 0x0c, 0xe4, 0x7b, + 0x01, 0x03, 0xe8, 0x6b, + 0x20, 0x93, 0xea, 0x6b, + 0x04, 0x0b, 0xf0, 0x6b, 0x40, 0x3c, 0x78, 0x00, 0xc7, 0x93, 0x26, 0x09, - 0x38, 0x93, 0xf0, 0x6b, + 0x38, 0x93, 0xf2, 0x6b, 0x00, 0x65, 0xcc, 0x41, - 0x80, 0x3c, 0x56, 0x6c, + 0x80, 0x3c, 0x58, 0x6c, 0x01, 0x06, 0x50, 0x31, 0x80, 0xb8, 0x70, 0x01, 0x00, 0x65, 0xcc, 0x41, 0x10, 0x3f, 0x06, 0x00, 0x10, 0x6a, 0x06, 0x00, 0x01, 0x3a, 0xca, 0x30, - 0x80, 0x65, 0x1c, 0x64, - 0x10, 0xb8, 0x40, 0x6c, + 0x80, 0x65, 0x1e, 0x64, + 0x10, 0xb8, 0x42, 0x6c, 0xc0, 0x3e, 0xca, 0x00, - 0x40, 0xb8, 0x0c, 0x6c, + 0x40, 0xb8, 0x0e, 0x6c, 0xbf, 0x65, 0xca, 0x08, - 0x20, 0xb8, 0x20, 0x7c, + 0x20, 0xb8, 0x22, 0x7c, 0x01, 0x65, 0x0c, 0x30, - 0x00, 0x65, 0xd8, 0x5d, - 0xa0, 0x3f, 0x28, 0x64, + 0x00, 0x65, 0xda, 0x5d, + 0xa0, 0x3f, 0x2a, 0x64, 0x23, 0xb8, 0x0c, 0x08, - 0x00, 0x65, 0xd8, 0x5d, - 0xa0, 0x3f, 0x28, 0x64, - 0x00, 0xbb, 0x20, 0x44, - 0xff, 0x65, 0x20, 0x64, - 0x00, 0x65, 0x40, 0x44, + 0x00, 0x65, 0xda, 0x5d, + 0xa0, 0x3f, 0x2a, 0x64, + 0x00, 0xbb, 0x22, 0x44, + 0xff, 0x65, 0x22, 0x64, + 0x00, 0x65, 0x42, 0x44, 0x40, 0x6a, 0x18, 0x00, 0x01, 0x65, 0x0c, 0x30, - 0x00, 0x65, 0xd8, 0x5d, - 0xa0, 0x3f, 0xfc, 0x73, + 0x00, 0x65, 0xda, 0x5d, + 0xa0, 0x3f, 0xfe, 0x73, 0x40, 0x6a, 0x18, 0x00, 0x01, 0x3a, 0xa6, 0x30, 0x08, 0x6a, 0x74, 0x00, 0x00, 0x65, 0xcc, 0x41, - 0x64, 0x6a, 0x68, 0x5d, - 0x80, 0x64, 0xd8, 0x6c, - 0x04, 0x64, 0x9a, 0x74, - 0x02, 0x64, 0xaa, 0x74, - 0x00, 0x6a, 0x60, 0x74, - 0x03, 0x64, 0xc8, 0x74, - 0x23, 0x64, 0x48, 0x74, - 0x08, 0x64, 0x5c, 0x74, - 0x61, 0x6a, 0xd8, 0x5e, - 0x00, 0x65, 0xd8, 0x5d, + 0x64, 0x6a, 0x6a, 0x5d, + 0x80, 0x64, 0xda, 0x6c, + 0x04, 0x64, 0x9c, 0x74, + 0x02, 0x64, 0xac, 0x74, + 0x00, 0x6a, 0x62, 0x74, + 0x03, 0x64, 0xca, 0x74, + 0x23, 0x64, 0x4a, 0x74, + 0x08, 0x64, 0x5e, 0x74, + 0x61, 0x6a, 0xda, 0x5e, + 0x00, 0x65, 0xda, 0x5d, 0x08, 0x51, 0xce, 0x71, - 0x00, 0x65, 0x40, 0x44, - 0x80, 0x04, 0x5a, 0x7c, - 0x51, 0x6a, 0x5e, 0x5d, - 0x01, 0x51, 0x5a, 0x64, - 0x01, 0xa4, 0x52, 0x7c, - 0x80, 0xba, 0x5c, 0x6c, - 0x41, 0x6a, 0xd8, 0x5e, - 0x00, 0x65, 0x5c, 0x44, - 0x21, 0x6a, 0xd8, 0x5e, - 0x00, 0x65, 0x5c, 0x44, - 0x07, 0x6a, 0x54, 0x5d, + 0x00, 0x65, 0x42, 0x44, + 0x80, 0x04, 0x5c, 0x7c, + 0x51, 0x6a, 0x60, 0x5d, + 0x01, 0x51, 0x5c, 0x64, + 0x01, 0xa4, 0x54, 0x7c, + 0x80, 0xba, 0x5e, 0x6c, + 0x41, 0x6a, 0xda, 0x5e, + 0x00, 0x65, 0x5e, 0x44, + 0x21, 0x6a, 0xda, 0x5e, + 0x00, 0x65, 0x5e, 0x44, + 0x07, 0x6a, 0x56, 0x5d, 0x01, 0x06, 0xd4, 0x30, 0x00, 0x65, 0xcc, 0x41, - 0x80, 0xb8, 0x56, 0x7c, - 0xc0, 0x3c, 0x6a, 0x7c, - 0x80, 0x3c, 0x56, 0x6c, - 0xff, 0xa8, 0x6a, 0x6c, - 0x40, 0x3c, 0x56, 0x6c, - 0x10, 0xb8, 0x6e, 0x7c, - 0xa1, 0x6a, 0xd8, 0x5e, - 0x01, 0xb4, 0x74, 0x6c, - 0x02, 0xb4, 0x76, 0x6c, - 0x01, 0xa4, 0x76, 0x7c, - 0xff, 0xa8, 0x86, 0x7c, + 0x80, 0xb8, 0x58, 0x7c, + 0xc0, 0x3c, 0x6c, 0x7c, + 0x80, 0x3c, 0x58, 0x6c, + 0xff, 0xa8, 0x6c, 0x6c, + 0x40, 0x3c, 0x58, 0x6c, + 0x10, 0xb8, 0x70, 0x7c, + 0xa1, 0x6a, 0xda, 0x5e, + 0x01, 0xb4, 0x76, 0x6c, + 0x02, 0xb4, 0x78, 0x6c, + 0x01, 0xa4, 0x78, 0x7c, + 0xff, 0xa8, 0x88, 0x7c, 0x04, 0xb4, 0x68, 0x01, 0x01, 0x6a, 0x76, 0x00, - 0x00, 0xbb, 0x12, 0x5e, - 0xff, 0xa8, 0x86, 0x7c, - 0x71, 0x6a, 0xd8, 0x5e, - 0x40, 0x51, 0x86, 0x64, - 0x00, 0x65, 0xb2, 0x5e, + 0x00, 0xbb, 0x14, 0x5e, + 0xff, 0xa8, 0x88, 0x7c, + 0x71, 0x6a, 0xda, 0x5e, + 0x40, 0x51, 0x88, 0x64, + 0x00, 0x65, 0xb4, 0x5e, 0x00, 0x65, 0xde, 0x41, - 0x00, 0xbb, 0x8a, 0x5c, + 0x00, 0xbb, 0x8c, 0x5c, 0x00, 0x65, 0xde, 0x41, - 0x00, 0x65, 0xb2, 0x5e, + 0x00, 0x65, 0xb4, 0x5e, 0x01, 0x65, 0xa2, 0x30, 0x01, 0xf8, 0xc8, 0x30, 0x01, 0x4e, 0xc8, 0x30, - 0x00, 0x6a, 0xb6, 0xdd, - 0x00, 0x51, 0xc8, 0x5d, + 0x00, 0x6a, 0xb8, 0xdd, + 0x00, 0x51, 0xca, 0x5d, 0x01, 0x4e, 0x9c, 0x18, 0x02, 0x6a, 0x22, 0x05, - 0xc0, 0x3c, 0x56, 0x6c, + 0xc0, 0x3c, 0x58, 0x6c, 0x04, 0xb8, 0x70, 0x01, - 0x00, 0x65, 0xd4, 0x5e, + 0x00, 0x65, 0xd6, 0x5e, 0x20, 0xb8, 0xde, 0x69, 0x01, 0xbb, 0xa2, 0x30, 0x3f, 0xba, 0x7c, 0x08, - 0x00, 0xb9, 0xce, 0x5c, + 0x00, 0xb9, 0xd0, 0x5c, 0x00, 0x65, 0xde, 0x41, 0x01, 0x06, 0xd4, 0x30, 0x20, 0x3c, 0xcc, 0x79, - 0x20, 0x3c, 0x5c, 0x7c, - 0x01, 0xa4, 0xb8, 0x7c, + 0x20, 0x3c, 0x5e, 0x7c, + 0x01, 0xa4, 0xba, 0x7c, 0x01, 0xb4, 0x68, 0x01, 0x00, 0x65, 0xcc, 0x41, - 0x00, 0x65, 0x5c, 0x44, + 0x00, 0x65, 0x5e, 0x44, 0x04, 0x14, 0x58, 0x31, 0x01, 0x06, 0xd4, 0x30, 0x08, 0xa0, 0x60, 0x31, 0xac, 0x6a, 0xcc, 0x00, - 0x14, 0x6a, 0xf4, 0x5d, + 0x14, 0x6a, 0xf6, 0x5d, 0x01, 0x06, 0xd4, 0x30, - 0xa0, 0x6a, 0xec, 0x5d, + 0xa0, 0x6a, 0xee, 0x5d, 0x00, 0x65, 0xcc, 0x41, 0xdf, 0x3c, 0x78, 0x08, 0x12, 0x01, 0x02, 0x00, - 0x00, 0x65, 0x5c, 0x44, + 0x00, 0x65, 0x5e, 0x44, 0x4c, 0x65, 0xcc, 0x28, 0x01, 0x3e, 0x20, 0x31, 0xd0, 0x66, 0xcc, 0x18, @@ -631,102 +632,102 @@ static uint8_t seqprog[] = { 0xd0, 0x65, 0xca, 0x18, 0x01, 0x3e, 0x20, 0x31, 0x30, 0x65, 0xd4, 0x18, - 0x00, 0x65, 0xe6, 0x4c, + 0x00, 0x65, 0xe8, 0x4c, 0xe1, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0xd4, 0x08, 0x20, 0x65, 0xd4, 0x18, - 0x00, 0x65, 0xee, 0x54, + 0x00, 0x65, 0xf0, 0x54, 0xe1, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0xd4, 0x08, 0x20, 0x65, 0xca, 0x18, 0xe0, 0x65, 0xd4, 0x18, - 0x00, 0x65, 0xf8, 0x4c, + 0x00, 0x65, 0xfa, 0x4c, 0xe1, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0xd4, 0x08, 0xd0, 0x65, 0xd4, 0x18, - 0x00, 0x65, 0x00, 0x55, + 0x00, 0x65, 0x02, 0x55, 0xe1, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0xd4, 0x08, 0x01, 0x6c, 0xa2, 0x30, - 0xff, 0x51, 0x12, 0x75, - 0x00, 0x51, 0x8e, 0x5d, + 0xff, 0x51, 0x14, 0x75, + 0x00, 0x51, 0x90, 0x5d, 0x01, 0x51, 0x20, 0x31, - 0x00, 0x65, 0x34, 0x45, + 0x00, 0x65, 0x36, 0x45, 0x3f, 0xba, 0xc8, 0x08, - 0x00, 0x3e, 0x34, 0x75, - 0x00, 0x65, 0xb0, 0x5e, + 0x00, 0x3e, 0x36, 0x75, + 0x00, 0x65, 0xb2, 0x5e, 0x80, 0x3c, 0x78, 0x00, 0x01, 0x06, 0xd4, 0x30, - 0x00, 0x65, 0xd8, 0x5d, + 0x00, 0x65, 0xda, 0x5d, 0x01, 0x3c, 0x78, 0x00, - 0xe0, 0x3f, 0x50, 0x65, + 0xe0, 0x3f, 0x52, 0x65, 0x02, 0x3c, 0x78, 0x00, - 0x20, 0x12, 0x50, 0x65, - 0x51, 0x6a, 0x5e, 0x5d, - 0x00, 0x51, 0x8e, 0x5d, - 0x51, 0x6a, 0x5e, 0x5d, + 0x20, 0x12, 0x52, 0x65, + 0x51, 0x6a, 0x60, 0x5d, + 0x00, 0x51, 0x90, 0x5d, + 0x51, 0x6a, 0x60, 0x5d, 0x01, 0x51, 0x20, 0x31, 0x04, 0x3c, 0x78, 0x00, 0x01, 0xb9, 0xc8, 0x30, - 0x00, 0x3d, 0x4e, 0x65, + 0x00, 0x3d, 0x50, 0x65, 0x08, 0x3c, 0x78, 0x00, 0x3f, 0xba, 0xc8, 0x08, - 0x00, 0x3e, 0x4e, 0x65, + 0x00, 0x3e, 0x50, 0x65, 0x10, 0x3c, 0x78, 0x00, - 0x04, 0xb8, 0x4e, 0x7d, + 0x04, 0xb8, 0x50, 0x7d, 0xfb, 0xb8, 0x70, 0x09, - 0x20, 0xb8, 0x44, 0x6d, + 0x20, 0xb8, 0x46, 0x6d, 0x01, 0x90, 0xc8, 0x30, 0xff, 0x6a, 0xa2, 0x00, - 0x00, 0x3d, 0xce, 0x5c, + 0x00, 0x3d, 0xd0, 0x5c, 0x01, 0x64, 0x20, 0x31, 0xff, 0x6a, 0x78, 0x08, 0x00, 0x65, 0xea, 0x58, - 0x10, 0xb8, 0x5c, 0x7c, - 0xff, 0x6a, 0x54, 0x5d, - 0x00, 0x65, 0x5c, 0x44, - 0x00, 0x65, 0xb0, 0x5e, - 0x31, 0x6a, 0xd8, 0x5e, - 0x00, 0x65, 0x5c, 0x44, + 0x10, 0xb8, 0x5e, 0x7c, + 0xff, 0x6a, 0x56, 0x5d, + 0x00, 0x65, 0x5e, 0x44, + 0x00, 0x65, 0xb2, 0x5e, + 0x31, 0x6a, 0xda, 0x5e, + 0x00, 0x65, 0x5e, 0x44, 0x10, 0x3f, 0x06, 0x00, 0x10, 0x6a, 0x06, 0x00, 0x01, 0x65, 0x74, 0x34, - 0x81, 0x6a, 0xd8, 0x5e, - 0x00, 0x65, 0x60, 0x45, + 0x81, 0x6a, 0xda, 0x5e, + 0x00, 0x65, 0x62, 0x45, 0x01, 0x06, 0xd4, 0x30, - 0x01, 0x0c, 0x60, 0x7d, - 0x04, 0x0c, 0x5a, 0x6d, + 0x01, 0x0c, 0x62, 0x7d, + 0x04, 0x0c, 0x5c, 0x6d, 0xe0, 0x03, 0x7e, 0x08, 0xe0, 0x3f, 0xcc, 0x61, 0x01, 0x65, 0xcc, 0x30, 0x01, 0x12, 0xda, 0x34, 0x01, 0x06, 0xd4, 0x34, - 0x01, 0x03, 0x6e, 0x6d, + 0x01, 0x03, 0x70, 0x6d, 0x40, 0x03, 0xcc, 0x08, 0x01, 0x65, 0x06, 0x30, 0x40, 0x65, 0xc8, 0x08, - 0x00, 0x66, 0x7c, 0x75, - 0x40, 0x65, 0x7c, 0x7d, - 0x00, 0x65, 0x7c, 0x5d, + 0x00, 0x66, 0x7e, 0x75, + 0x40, 0x65, 0x7e, 0x7d, + 0x00, 0x65, 0x7e, 0x5d, 0xff, 0x6a, 0xd4, 0x08, 0xff, 0x6a, 0xd4, 0x08, 0xff, 0x6a, 0xd4, 0x08, 0xff, 0x6a, 0xd4, 0x0c, 0x08, 0x01, 0x02, 0x00, - 0x02, 0x0b, 0x86, 0x7d, + 0x02, 0x0b, 0x88, 0x7d, 0x01, 0x65, 0x0c, 0x30, - 0x02, 0x0b, 0x8a, 0x7d, + 0x02, 0x0b, 0x8c, 0x7d, 0xf7, 0x01, 0x02, 0x0c, 0x01, 0x65, 0xc8, 0x30, - 0xff, 0x41, 0xae, 0x75, + 0xff, 0x41, 0xb0, 0x75, 0x01, 0x41, 0x20, 0x31, 0xff, 0x6a, 0xa4, 0x00, - 0x00, 0x65, 0x9e, 0x45, - 0xff, 0xbf, 0xae, 0x75, + 0x00, 0x65, 0xa0, 0x45, + 0xff, 0xbf, 0xb0, 0x75, 0x01, 0x90, 0xa4, 0x30, 0x01, 0xbf, 0x20, 0x31, - 0x00, 0xbb, 0x98, 0x65, - 0xff, 0x52, 0xac, 0x75, + 0x00, 0xbb, 0x9a, 0x65, + 0xff, 0x52, 0xae, 0x75, 0x01, 0xbf, 0xcc, 0x30, 0x01, 0x90, 0xca, 0x30, 0x01, 0x52, 0x20, 0x31, @@ -734,28 +735,28 @@ static uint8_t seqprog[] = { 0x01, 0x65, 0x20, 0x35, 0x01, 0xbf, 0x82, 0x34, 0x01, 0x64, 0xa2, 0x30, - 0x00, 0x6a, 0xc0, 0x5e, + 0x00, 0x6a, 0xc2, 0x5e, 0x0d, 0x6a, 0x76, 0x00, - 0x00, 0x51, 0x12, 0x46, + 0x00, 0x51, 0x14, 0x46, 0x01, 0x65, 0xa4, 0x30, 0xe0, 0x6a, 0xcc, 0x00, - 0x48, 0x6a, 0x06, 0x5e, + 0x48, 0x6a, 0x08, 0x5e, 0x01, 0x6a, 0xd0, 0x01, 0x01, 0x6a, 0xdc, 0x05, 0x88, 0x6a, 0xcc, 0x00, - 0x48, 0x6a, 0x06, 0x5e, - 0x01, 0x6a, 0xe0, 0x5d, + 0x48, 0x6a, 0x08, 0x5e, + 0x01, 0x6a, 0xe2, 0x5d, 0x01, 0x6a, 0x26, 0x05, 0x01, 0x65, 0xd8, 0x31, 0x09, 0xee, 0xdc, 0x01, - 0x80, 0xee, 0xcc, 0x7d, + 0x80, 0xee, 0xce, 0x7d, 0xff, 0x6a, 0xdc, 0x0d, 0x01, 0x65, 0x32, 0x31, 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0xa8, 0x46, - 0x81, 0x6a, 0xd8, 0x5e, - 0x01, 0x0c, 0xd8, 0x7d, - 0x04, 0x0c, 0xd6, 0x6d, + 0x00, 0x65, 0xaa, 0x46, + 0x81, 0x6a, 0xda, 0x5e, + 0x01, 0x0c, 0xda, 0x7d, + 0x04, 0x0c, 0xd8, 0x6d, 0xe0, 0x03, 0x06, 0x08, 0xe0, 0x03, 0x7e, 0x0c, 0x01, 0x65, 0x18, 0x31, @@ -774,7 +775,7 @@ static uint8_t seqprog[] = { 0x01, 0x6c, 0xda, 0x34, 0x3d, 0x64, 0xa4, 0x28, 0x55, 0x64, 0xc8, 0x28, - 0x00, 0x65, 0x06, 0x46, + 0x00, 0x65, 0x08, 0x46, 0x2e, 0x64, 0xa4, 0x28, 0x66, 0x64, 0xc8, 0x28, 0x00, 0x6c, 0xda, 0x18, @@ -785,63 +786,63 @@ static uint8_t seqprog[] = { 0x00, 0x6c, 0xda, 0x24, 0x01, 0x65, 0xc8, 0x30, 0xe0, 0x6a, 0xcc, 0x00, - 0x44, 0x6a, 0x02, 0x5e, + 0x44, 0x6a, 0x04, 0x5e, 0x01, 0x90, 0xe2, 0x31, - 0x04, 0x3b, 0x26, 0x7e, + 0x04, 0x3b, 0x28, 0x7e, 0x30, 0x6a, 0xd0, 0x01, 0x20, 0x6a, 0xd0, 0x01, 0x1d, 0x6a, 0xdc, 0x01, - 0xdc, 0xee, 0x22, 0x66, - 0x00, 0x65, 0x3e, 0x46, + 0xdc, 0xee, 0x24, 0x66, + 0x00, 0x65, 0x40, 0x46, 0x20, 0x6a, 0xd0, 0x01, 0x01, 0x6a, 0xdc, 0x01, 0x20, 0xa0, 0xd8, 0x31, 0x09, 0xee, 0xdc, 0x01, - 0x80, 0xee, 0x2e, 0x7e, + 0x80, 0xee, 0x30, 0x7e, 0x11, 0x6a, 0xdc, 0x01, - 0x50, 0xee, 0x32, 0x66, + 0x50, 0xee, 0x34, 0x66, 0x20, 0x6a, 0xd0, 0x01, 0x09, 0x6a, 0xdc, 0x01, - 0x88, 0xee, 0x38, 0x66, + 0x88, 0xee, 0x3a, 0x66, 0x19, 0x6a, 0xdc, 0x01, - 0xd8, 0xee, 0x3c, 0x66, + 0xd8, 0xee, 0x3e, 0x66, 0xff, 0x6a, 0xdc, 0x09, - 0x18, 0xee, 0x40, 0x6e, + 0x18, 0xee, 0x42, 0x6e, 0xff, 0x6a, 0xd4, 0x0c, 0x88, 0x6a, 0xcc, 0x00, - 0x44, 0x6a, 0x02, 0x5e, - 0x20, 0x6a, 0xe0, 0x5d, + 0x44, 0x6a, 0x04, 0x5e, + 0x20, 0x6a, 0xe2, 0x5d, 0x01, 0x3b, 0x26, 0x31, - 0x04, 0x3b, 0x5a, 0x6e, + 0x04, 0x3b, 0x5c, 0x6e, 0xa0, 0x6a, 0xca, 0x00, 0x20, 0x65, 0xc8, 0x18, - 0x00, 0x65, 0x98, 0x5e, - 0x00, 0x65, 0x52, 0x66, + 0x00, 0x65, 0x9a, 0x5e, + 0x00, 0x65, 0x54, 0x66, 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0xa8, 0x46, + 0x00, 0x65, 0xaa, 0x46, 0xa0, 0x6a, 0xcc, 0x00, 0xff, 0x6a, 0xc8, 0x08, - 0x20, 0x94, 0x5e, 0x6e, - 0x10, 0x94, 0x60, 0x6e, - 0x08, 0x94, 0x7a, 0x6e, - 0x08, 0x94, 0x7a, 0x6e, - 0x08, 0x94, 0x7a, 0x6e, + 0x20, 0x94, 0x60, 0x6e, + 0x10, 0x94, 0x62, 0x6e, + 0x08, 0x94, 0x7c, 0x6e, + 0x08, 0x94, 0x7c, 0x6e, + 0x08, 0x94, 0x7c, 0x6e, 0xff, 0x8c, 0xc8, 0x10, 0xc1, 0x64, 0xc8, 0x18, 0xf8, 0x64, 0xc8, 0x08, 0x01, 0x99, 0xda, 0x30, - 0x00, 0x66, 0x6e, 0x66, - 0xc0, 0x66, 0xaa, 0x76, + 0x00, 0x66, 0x70, 0x66, + 0xc0, 0x66, 0xac, 0x76, 0x60, 0x66, 0xc8, 0x18, 0x3d, 0x64, 0xc8, 0x28, - 0x00, 0x65, 0x5e, 0x46, + 0x00, 0x65, 0x60, 0x46, 0xf7, 0x93, 0x26, 0x09, - 0x08, 0x93, 0x7c, 0x6e, + 0x08, 0x93, 0x7e, 0x6e, 0x00, 0x62, 0xc4, 0x18, - 0x00, 0x65, 0xa8, 0x5e, - 0x00, 0x65, 0x88, 0x5e, - 0x00, 0x65, 0x88, 0x5e, - 0x00, 0x65, 0x88, 0x5e, + 0x00, 0x65, 0xaa, 0x5e, + 0x00, 0x65, 0x8a, 0x5e, + 0x00, 0x65, 0x8a, 0x5e, + 0x00, 0x65, 0x8a, 0x5e, 0x01, 0x99, 0xda, 0x30, 0x01, 0x99, 0xda, 0x30, 0x01, 0x99, 0xda, 0x30, @@ -858,11 +859,11 @@ static uint8_t seqprog[] = { 0x01, 0x6c, 0x32, 0x31, 0x01, 0x6c, 0x32, 0x31, 0x01, 0x6c, 0x32, 0x35, - 0x08, 0x94, 0xa8, 0x7e, + 0x08, 0x94, 0xaa, 0x7e, 0xf7, 0x93, 0x26, 0x09, - 0x08, 0x93, 0xac, 0x6e, + 0x08, 0x93, 0xae, 0x6e, 0xff, 0x6a, 0xd4, 0x0c, - 0x04, 0xb8, 0xd4, 0x6e, + 0x04, 0xb8, 0xd6, 0x6e, 0x01, 0x42, 0x7e, 0x31, 0xff, 0x6a, 0x76, 0x01, 0x01, 0x90, 0x84, 0x34, @@ -870,14 +871,14 @@ static uint8_t seqprog[] = { 0x01, 0x85, 0x0a, 0x01, 0x7f, 0x65, 0x10, 0x09, 0xfe, 0x85, 0x0a, 0x0d, - 0xff, 0x42, 0xd0, 0x66, - 0xff, 0x41, 0xc8, 0x66, - 0xd1, 0x6a, 0xd8, 0x5e, + 0xff, 0x42, 0xd2, 0x66, + 0xff, 0x41, 0xca, 0x66, + 0xd1, 0x6a, 0xda, 0x5e, 0xff, 0x6a, 0xca, 0x04, 0x01, 0x41, 0x20, 0x31, 0x01, 0xbf, 0x82, 0x30, 0x01, 0x6a, 0x76, 0x00, - 0x00, 0xbb, 0x12, 0x46, + 0x00, 0xbb, 0x14, 0x46, 0x01, 0x42, 0x20, 0x31, 0x01, 0xbf, 0x84, 0x34, 0x01, 0x41, 0x7e, 0x31, @@ -941,7 +942,7 @@ static ahc_patch_func_t ahc_patch17_func; static int ahc_patch17_func(struct ahc_softc *ahc) { - return ((ahc->flags & AHC_TMODE_WIDEODD_BUG) != 0); + return ((ahc->bugs & AHC_TMODE_WIDEODD_BUG) != 0); } static ahc_patch_func_t ahc_patch16_func; @@ -1142,152 +1143,152 @@ static struct patch { { ahc_patch0_func, 196, 1, 1 }, { ahc_patch9_func, 212, 6, 2 }, { ahc_patch0_func, 218, 6, 1 }, - { ahc_patch8_func, 226, 20, 2 }, + { ahc_patch8_func, 226, 21, 2 }, { ahc_patch1_func, 241, 1, 1 }, - { ahc_patch1_func, 248, 1, 2 }, - { ahc_patch0_func, 249, 2, 2 }, - { ahc_patch11_func, 250, 1, 1 }, - { ahc_patch9_func, 258, 27, 3 }, - { ahc_patch1_func, 274, 10, 2 }, - { ahc_patch13_func, 277, 1, 1 }, - { ahc_patch14_func, 285, 14, 1 }, - { ahc_patch1_func, 301, 1, 2 }, - { ahc_patch0_func, 302, 1, 1 }, - { ahc_patch9_func, 305, 1, 1 }, - { ahc_patch13_func, 310, 1, 1 }, - { ahc_patch9_func, 311, 2, 2 }, - { ahc_patch0_func, 313, 4, 1 }, - { ahc_patch14_func, 317, 1, 1 }, - { ahc_patch15_func, 319, 2, 3 }, - { ahc_patch9_func, 319, 1, 2 }, - { ahc_patch0_func, 320, 1, 1 }, - { ahc_patch6_func, 325, 1, 2 }, - { ahc_patch0_func, 326, 1, 1 }, - { ahc_patch1_func, 330, 47, 11 }, - { ahc_patch6_func, 337, 2, 4 }, - { ahc_patch7_func, 337, 1, 1 }, - { ahc_patch8_func, 338, 1, 1 }, - { ahc_patch0_func, 339, 1, 1 }, - { ahc_patch16_func, 340, 1, 1 }, - { ahc_patch6_func, 356, 6, 3 }, - { ahc_patch16_func, 356, 5, 1 }, - { ahc_patch0_func, 362, 7, 1 }, - { ahc_patch13_func, 372, 5, 1 }, - { ahc_patch0_func, 377, 52, 17 }, - { ahc_patch14_func, 377, 1, 1 }, - { ahc_patch7_func, 379, 2, 2 }, - { ahc_patch17_func, 380, 1, 1 }, - { ahc_patch9_func, 383, 1, 1 }, - { ahc_patch18_func, 390, 1, 1 }, - { ahc_patch14_func, 395, 9, 3 }, - { ahc_patch9_func, 396, 3, 2 }, - { ahc_patch0_func, 399, 3, 1 }, - { ahc_patch9_func, 407, 6, 2 }, - { ahc_patch0_func, 413, 9, 2 }, - { ahc_patch13_func, 413, 1, 1 }, - { ahc_patch13_func, 422, 2, 1 }, - { ahc_patch14_func, 424, 1, 1 }, - { ahc_patch9_func, 426, 1, 2 }, - { ahc_patch0_func, 427, 1, 1 }, - { ahc_patch7_func, 428, 1, 1 }, + { ahc_patch1_func, 249, 1, 2 }, + { ahc_patch0_func, 250, 2, 2 }, + { ahc_patch11_func, 251, 1, 1 }, + { ahc_patch9_func, 259, 27, 3 }, + { ahc_patch1_func, 275, 10, 2 }, + { ahc_patch13_func, 278, 1, 1 }, + { ahc_patch14_func, 286, 14, 1 }, + { ahc_patch1_func, 302, 1, 2 }, + { ahc_patch0_func, 303, 1, 1 }, + { ahc_patch9_func, 306, 1, 1 }, + { ahc_patch13_func, 311, 1, 1 }, + { ahc_patch9_func, 312, 2, 2 }, + { ahc_patch0_func, 314, 4, 1 }, + { ahc_patch14_func, 318, 1, 1 }, + { ahc_patch15_func, 320, 2, 3 }, + { ahc_patch9_func, 320, 1, 2 }, + { ahc_patch0_func, 321, 1, 1 }, + { ahc_patch6_func, 326, 1, 2 }, + { ahc_patch0_func, 327, 1, 1 }, + { ahc_patch1_func, 331, 47, 11 }, + { ahc_patch6_func, 338, 2, 4 }, + { ahc_patch7_func, 338, 1, 1 }, + { ahc_patch8_func, 339, 1, 1 }, + { ahc_patch0_func, 340, 1, 1 }, + { ahc_patch16_func, 341, 1, 1 }, + { ahc_patch6_func, 357, 6, 3 }, + { ahc_patch16_func, 357, 5, 1 }, + { ahc_patch0_func, 363, 7, 1 }, + { ahc_patch13_func, 373, 5, 1 }, + { ahc_patch0_func, 378, 52, 17 }, + { ahc_patch14_func, 378, 1, 1 }, + { ahc_patch7_func, 380, 2, 2 }, + { ahc_patch17_func, 381, 1, 1 }, + { ahc_patch9_func, 384, 1, 1 }, + { ahc_patch18_func, 391, 1, 1 }, + { ahc_patch14_func, 396, 9, 3 }, + { ahc_patch9_func, 397, 3, 2 }, + { ahc_patch0_func, 400, 3, 1 }, + { ahc_patch9_func, 408, 6, 2 }, + { ahc_patch0_func, 414, 9, 2 }, + { ahc_patch13_func, 414, 1, 1 }, + { ahc_patch13_func, 423, 2, 1 }, + { ahc_patch14_func, 425, 1, 1 }, + { ahc_patch9_func, 427, 1, 2 }, + { ahc_patch0_func, 428, 1, 1 }, { ahc_patch7_func, 429, 1, 1 }, - { ahc_patch8_func, 430, 3, 3 }, - { ahc_patch6_func, 431, 1, 2 }, - { ahc_patch0_func, 432, 1, 1 }, - { ahc_patch9_func, 433, 1, 1 }, - { ahc_patch15_func, 434, 1, 2 }, - { ahc_patch13_func, 434, 1, 1 }, - { ahc_patch14_func, 436, 9, 4 }, - { ahc_patch9_func, 436, 1, 1 }, - { ahc_patch9_func, 443, 2, 1 }, - { ahc_patch0_func, 445, 4, 3 }, - { ahc_patch9_func, 445, 1, 2 }, - { ahc_patch0_func, 446, 3, 1 }, - { ahc_patch1_func, 450, 2, 1 }, - { ahc_patch7_func, 452, 10, 2 }, - { ahc_patch0_func, 462, 1, 1 }, - { ahc_patch8_func, 463, 118, 22 }, - { ahc_patch1_func, 465, 3, 2 }, - { ahc_patch0_func, 468, 5, 3 }, - { ahc_patch9_func, 468, 2, 2 }, - { ahc_patch0_func, 470, 3, 1 }, - { ahc_patch1_func, 475, 2, 2 }, - { ahc_patch0_func, 477, 6, 3 }, - { ahc_patch9_func, 477, 2, 2 }, - { ahc_patch0_func, 479, 3, 1 }, - { ahc_patch1_func, 485, 2, 2 }, - { ahc_patch0_func, 487, 9, 7 }, - { ahc_patch9_func, 487, 5, 6 }, - { ahc_patch19_func, 487, 1, 2 }, - { ahc_patch0_func, 488, 1, 1 }, - { ahc_patch19_func, 490, 1, 2 }, - { ahc_patch0_func, 491, 1, 1 }, - { ahc_patch0_func, 492, 4, 1 }, - { ahc_patch6_func, 497, 3, 2 }, - { ahc_patch0_func, 500, 1, 1 }, - { ahc_patch6_func, 510, 1, 2 }, - { ahc_patch0_func, 511, 1, 1 }, - { ahc_patch20_func, 548, 7, 1 }, - { ahc_patch3_func, 583, 1, 2 }, - { ahc_patch0_func, 584, 1, 1 }, - { ahc_patch21_func, 587, 1, 1 }, - { ahc_patch8_func, 589, 106, 33 }, - { ahc_patch4_func, 591, 1, 1 }, - { ahc_patch1_func, 597, 2, 2 }, - { ahc_patch0_func, 599, 1, 1 }, - { ahc_patch1_func, 602, 1, 2 }, - { ahc_patch0_func, 603, 1, 1 }, - { ahc_patch9_func, 604, 3, 3 }, - { ahc_patch15_func, 605, 1, 1 }, - { ahc_patch0_func, 607, 4, 1 }, - { ahc_patch19_func, 616, 2, 2 }, - { ahc_patch0_func, 618, 1, 1 }, - { ahc_patch19_func, 622, 10, 3 }, - { ahc_patch5_func, 624, 8, 1 }, - { ahc_patch0_func, 632, 9, 2 }, - { ahc_patch5_func, 633, 8, 1 }, - { ahc_patch4_func, 643, 1, 2 }, - { ahc_patch0_func, 644, 1, 1 }, - { ahc_patch19_func, 645, 1, 2 }, - { ahc_patch0_func, 646, 3, 2 }, - { ahc_patch4_func, 648, 1, 1 }, - { ahc_patch5_func, 649, 1, 1 }, - { ahc_patch5_func, 652, 1, 1 }, - { ahc_patch5_func, 654, 1, 1 }, - { ahc_patch4_func, 656, 2, 2 }, - { ahc_patch0_func, 658, 2, 1 }, - { ahc_patch5_func, 660, 1, 1 }, - { ahc_patch5_func, 663, 1, 1 }, - { ahc_patch5_func, 666, 1, 1 }, - { ahc_patch19_func, 670, 1, 1 }, - { ahc_patch19_func, 673, 1, 1 }, - { ahc_patch4_func, 679, 1, 1 }, - { ahc_patch6_func, 682, 1, 2 }, - { ahc_patch0_func, 683, 1, 1 }, - { ahc_patch7_func, 695, 16, 1 }, - { ahc_patch4_func, 711, 20, 1 }, - { ahc_patch9_func, 732, 4, 2 }, - { ahc_patch0_func, 736, 4, 1 }, - { ahc_patch9_func, 740, 4, 2 }, - { ahc_patch0_func, 744, 3, 1 }, - { ahc_patch6_func, 750, 1, 1 }, - { ahc_patch22_func, 752, 14, 1 }, - { ahc_patch7_func, 766, 3, 1 }, - { ahc_patch9_func, 778, 24, 8 }, - { ahc_patch19_func, 782, 1, 2 }, - { ahc_patch0_func, 783, 1, 1 }, - { ahc_patch15_func, 788, 4, 2 }, - { ahc_patch0_func, 792, 7, 3 }, - { ahc_patch23_func, 792, 5, 2 }, - { ahc_patch0_func, 797, 2, 1 }, - { ahc_patch0_func, 802, 42, 3 }, - { ahc_patch18_func, 814, 18, 2 }, - { ahc_patch0_func, 832, 1, 1 }, - { ahc_patch4_func, 856, 1, 1 }, - { ahc_patch4_func, 857, 3, 2 }, - { ahc_patch0_func, 860, 1, 1 }, - { ahc_patch13_func, 861, 3, 1 }, - { ahc_patch4_func, 864, 12, 1 } + { ahc_patch7_func, 430, 1, 1 }, + { ahc_patch8_func, 431, 3, 3 }, + { ahc_patch6_func, 432, 1, 2 }, + { ahc_patch0_func, 433, 1, 1 }, + { ahc_patch9_func, 434, 1, 1 }, + { ahc_patch15_func, 435, 1, 2 }, + { ahc_patch13_func, 435, 1, 1 }, + { ahc_patch14_func, 437, 9, 4 }, + { ahc_patch9_func, 437, 1, 1 }, + { ahc_patch9_func, 444, 2, 1 }, + { ahc_patch0_func, 446, 4, 3 }, + { ahc_patch9_func, 446, 1, 2 }, + { ahc_patch0_func, 447, 3, 1 }, + { ahc_patch1_func, 451, 2, 1 }, + { ahc_patch7_func, 453, 10, 2 }, + { ahc_patch0_func, 463, 1, 1 }, + { ahc_patch8_func, 464, 118, 22 }, + { ahc_patch1_func, 466, 3, 2 }, + { ahc_patch0_func, 469, 5, 3 }, + { ahc_patch9_func, 469, 2, 2 }, + { ahc_patch0_func, 471, 3, 1 }, + { ahc_patch1_func, 476, 2, 2 }, + { ahc_patch0_func, 478, 6, 3 }, + { ahc_patch9_func, 478, 2, 2 }, + { ahc_patch0_func, 480, 3, 1 }, + { ahc_patch1_func, 486, 2, 2 }, + { ahc_patch0_func, 488, 9, 7 }, + { ahc_patch9_func, 488, 5, 6 }, + { ahc_patch19_func, 488, 1, 2 }, + { ahc_patch0_func, 489, 1, 1 }, + { ahc_patch19_func, 491, 1, 2 }, + { ahc_patch0_func, 492, 1, 1 }, + { ahc_patch0_func, 493, 4, 1 }, + { ahc_patch6_func, 498, 3, 2 }, + { ahc_patch0_func, 501, 1, 1 }, + { ahc_patch6_func, 511, 1, 2 }, + { ahc_patch0_func, 512, 1, 1 }, + { ahc_patch20_func, 549, 7, 1 }, + { ahc_patch3_func, 584, 1, 2 }, + { ahc_patch0_func, 585, 1, 1 }, + { ahc_patch21_func, 588, 1, 1 }, + { ahc_patch8_func, 590, 106, 33 }, + { ahc_patch4_func, 592, 1, 1 }, + { ahc_patch1_func, 598, 2, 2 }, + { ahc_patch0_func, 600, 1, 1 }, + { ahc_patch1_func, 603, 1, 2 }, + { ahc_patch0_func, 604, 1, 1 }, + { ahc_patch9_func, 605, 3, 3 }, + { ahc_patch15_func, 606, 1, 1 }, + { ahc_patch0_func, 608, 4, 1 }, + { ahc_patch19_func, 617, 2, 2 }, + { ahc_patch0_func, 619, 1, 1 }, + { ahc_patch19_func, 623, 10, 3 }, + { ahc_patch5_func, 625, 8, 1 }, + { ahc_patch0_func, 633, 9, 2 }, + { ahc_patch5_func, 634, 8, 1 }, + { ahc_patch4_func, 644, 1, 2 }, + { ahc_patch0_func, 645, 1, 1 }, + { ahc_patch19_func, 646, 1, 2 }, + { ahc_patch0_func, 647, 3, 2 }, + { ahc_patch4_func, 649, 1, 1 }, + { ahc_patch5_func, 650, 1, 1 }, + { ahc_patch5_func, 653, 1, 1 }, + { ahc_patch5_func, 655, 1, 1 }, + { ahc_patch4_func, 657, 2, 2 }, + { ahc_patch0_func, 659, 2, 1 }, + { ahc_patch5_func, 661, 1, 1 }, + { ahc_patch5_func, 664, 1, 1 }, + { ahc_patch5_func, 667, 1, 1 }, + { ahc_patch19_func, 671, 1, 1 }, + { ahc_patch19_func, 674, 1, 1 }, + { ahc_patch4_func, 680, 1, 1 }, + { ahc_patch6_func, 683, 1, 2 }, + { ahc_patch0_func, 684, 1, 1 }, + { ahc_patch7_func, 696, 16, 1 }, + { ahc_patch4_func, 712, 20, 1 }, + { ahc_patch9_func, 733, 4, 2 }, + { ahc_patch0_func, 737, 4, 1 }, + { ahc_patch9_func, 741, 4, 2 }, + { ahc_patch0_func, 745, 3, 1 }, + { ahc_patch6_func, 751, 1, 1 }, + { ahc_patch22_func, 753, 14, 1 }, + { ahc_patch7_func, 767, 3, 1 }, + { ahc_patch9_func, 779, 24, 8 }, + { ahc_patch19_func, 783, 1, 2 }, + { ahc_patch0_func, 784, 1, 1 }, + { ahc_patch15_func, 789, 4, 2 }, + { ahc_patch0_func, 793, 7, 3 }, + { ahc_patch23_func, 793, 5, 2 }, + { ahc_patch0_func, 798, 2, 1 }, + { ahc_patch0_func, 803, 42, 3 }, + { ahc_patch18_func, 815, 18, 2 }, + { ahc_patch0_func, 833, 1, 1 }, + { ahc_patch4_func, 857, 1, 1 }, + { ahc_patch4_func, 858, 3, 2 }, + { ahc_patch0_func, 861, 1, 1 }, + { ahc_patch13_func, 862, 3, 1 }, + { ahc_patch4_func, 865, 12, 1 } }; static struct cs { @@ -1296,11 +1297,11 @@ static struct cs { } critical_sections[] = { { 11, 18 }, { 21, 30 }, - { 711, 727 }, - { 857, 860 }, - { 864, 870 }, - { 872, 874 }, - { 874, 876 } + { 712, 728 }, + { 858, 861 }, + { 865, 871 }, + { 873, 875 }, + { 875, 877 } }; static const int num_critical_sections = sizeof(critical_sections) From fc789a93994858b5e5a46afb96d0dcf6cc1b6f08 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Fri, 5 Aug 2005 16:24:54 -0500 Subject: [PATCH 032/114] [SCSI] aic7xxx/79xx: fix another potential panic due to a non existent target I ran into this one sending bus resets across the hardware. Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic79xx_osm.c | 4 ++-- drivers/scsi/aic7xxx/aic7xxx_osm.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index 40f32bb23972..acaeebd50465 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -1617,9 +1617,9 @@ ahd_send_async(struct ahd_softc *ahd, char channel, * are identical to those last reported. */ starget = ahd->platform_data->starget[target]; - targ = scsi_transport_target_data(starget); - if (targ == NULL) + if (starget == NULL) break; + targ = scsi_transport_target_data(starget); target_ppr_options = (spi_dt(starget) ? MSG_EXT_PPR_DT_REQ : 0) diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index e39361ac6a44..3fbc10e58cc2 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -1618,9 +1618,9 @@ ahc_send_async(struct ahc_softc *ahc, char channel, if (channel == 'B') target_offset += 8; starget = ahc->platform_data->starget[target_offset]; - targ = scsi_transport_target_data(starget); - if (targ == NULL) + if (starget == NULL) break; + targ = scsi_transport_target_data(starget); target_ppr_options = (spi_dt(starget) ? MSG_EXT_PPR_DT_REQ : 0) From bed30de47b034b5f28fb7db2fae4860b9d9c0622 Mon Sep 17 00:00:00 2001 From: Mark Haverkamp Date: Wed, 3 Aug 2005 15:38:51 -0700 Subject: [PATCH 033/114] [SCSI] aacraid: interupt mitigation Received from Mark Salyzyn from Adaptec: If more than two commands are outstanding to the controller, there is no need to notify the adapter via a PCI bus transaction of additional commands added into the queue; it will get to them when it works through the produce/consumer indexes. This reduced the PCI traffic in the driver to submit a command to the queue to near zero allowing a significant number of commands to be turned around with no need to block for the PCI bridge to flush the notify request to the adapter. Interrupt mitigation has always been present in the driver; it was turned off because of a bug that prevented one from realizing the usefulness of the feature. This bug is fixed in this patch. Signed-off-by: Mark Haverkamp Signed-off-by: James Bottomley --- drivers/scsi/aacraid/comminit.c | 4 +++- drivers/scsi/aacraid/commsup.c | 20 +++++++++++++++++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c index 43557bf661f6..75abd0453289 100644 --- a/drivers/scsi/aacraid/comminit.c +++ b/drivers/scsi/aacraid/comminit.c @@ -44,7 +44,9 @@ #include "aacraid.h" -struct aac_common aac_config; +struct aac_common aac_config = { + .irq_mod = 1 +}; static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long commsize, unsigned long commalign) { diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index 5322865942e2..a1d303f03480 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -254,6 +254,7 @@ static void fib_dealloc(struct fib * fibptr) static int aac_get_entry (struct aac_dev * dev, u32 qid, struct aac_entry **entry, u32 * index, unsigned long *nonotify) { struct aac_queue * q; + unsigned long idx; /* * All of the queues wrap when they reach the end, so we check @@ -263,10 +264,23 @@ static int aac_get_entry (struct aac_dev * dev, u32 qid, struct aac_entry **entr */ q = &dev->queues->queue[qid]; - - *index = le32_to_cpu(*(q->headers.producer)); - if ((*index - 2) == le32_to_cpu(*(q->headers.consumer))) + + idx = *index = le32_to_cpu(*(q->headers.producer)); + /* Interrupt Moderation, only interrupt for first two entries */ + if (idx != le32_to_cpu(*(q->headers.consumer))) { + if (--idx == 0) { + if (qid == AdapHighCmdQueue) + idx = ADAP_HIGH_CMD_ENTRIES; + else if (qid == AdapNormCmdQueue) + idx = ADAP_NORM_CMD_ENTRIES; + else if (qid == AdapHighRespQueue) + idx = ADAP_HIGH_RESP_ENTRIES; + else if (qid == AdapNormRespQueue) + idx = ADAP_NORM_RESP_ENTRIES; + } + if (idx != le32_to_cpu(*(q->headers.consumer))) *nonotify = 1; + } if (qid == AdapHighCmdQueue) { if (*index >= ADAP_HIGH_CMD_ENTRIES) From c7f476023f57145357df32346b7de9202ce47d5f Mon Sep 17 00:00:00 2001 From: Mark Haverkamp Date: Wed, 3 Aug 2005 15:38:55 -0700 Subject: [PATCH 034/114] [SCSI] aacraid: driver version update Received from Mark Salyzyn from Adaptec. Fixes a bug in check_revision. It should return the driver version not the firmware version. Update driver version number. Update driver version string. Signed-off-by: Mark Haverkamp Signed-off-by: James Bottomley --- drivers/scsi/aacraid/aacraid.h | 8 +++++--- drivers/scsi/aacraid/commctrl.c | 16 +++++++++++++--- drivers/scsi/aacraid/linit.c | 21 ++++++++++++++++----- 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index 3a11a536c0da..ddbbb85b3a7c 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h @@ -1512,11 +1512,12 @@ struct fib_ioctl struct revision { - u32 compat; - u32 version; - u32 build; + __le32 compat; + __le32 version; + __le32 build; }; + /* * Ugly - non Linux like ioctl coding for back compat. */ @@ -1737,3 +1738,4 @@ int aac_get_adapter_info(struct aac_dev* dev); int aac_send_shutdown(struct aac_dev *dev); extern int numacb; extern int acbsize; +extern char aac_driver_version[]; diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c index 85387099aab2..8fceff9be1be 100644 --- a/drivers/scsi/aacraid/commctrl.c +++ b/drivers/scsi/aacraid/commctrl.c @@ -405,10 +405,20 @@ static int close_getadapter_fib(struct aac_dev * dev, void __user *arg) static int check_revision(struct aac_dev *dev, void __user *arg) { struct revision response; + char *driver_version = aac_driver_version; + u32 version; - response.compat = 1; - response.version = le32_to_cpu(dev->adapter_info.kernelrev); - response.build = le32_to_cpu(dev->adapter_info.kernelbuild); + response.compat = cpu_to_le32(1); + version = (simple_strtol(driver_version, + &driver_version, 10) << 24) | 0x00000400; + version += simple_strtol(driver_version + 1, &driver_version, 10) << 16; + version += simple_strtol(driver_version + 1, NULL, 10); + response.version = cpu_to_le32(version); +# if (defined(AAC_DRIVER_BUILD)) + response.build = cpu_to_le32(AAC_DRIVER_BUILD); +# else + response.build = cpu_to_le32(9999); +# endif if (copy_to_user(arg, &response, sizeof(response))) return -EFAULT; diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index c1a4f978fcba..b6dda99f5083 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -27,8 +27,11 @@ * Abstract: Linux Driver entry module for Adaptec RAID Array Controller */ -#define AAC_DRIVER_VERSION "1.1.2-lk2" -#define AAC_DRIVER_BUILD_DATE __DATE__ +#define AAC_DRIVER_VERSION "1.1-4" +#ifndef AAC_DRIVER_BRANCH +#define AAC_DRIVER_BRANCH "" +#endif +#define AAC_DRIVER_BUILD_DATE __DATE__ " " __TIME__ #define AAC_DRIVERNAME "aacraid" #include @@ -58,16 +61,24 @@ #include "aacraid.h" +#ifdef AAC_DRIVER_BUILD +#define _str(x) #x +#define str(x) _str(x) +#define AAC_DRIVER_FULL_VERSION AAC_DRIVER_VERSION "[" str(AAC_DRIVER_BUILD) "]" AAC_DRIVER_BRANCH +#else +#define AAC_DRIVER_FULL_VERSION AAC_DRIVER_VERSION AAC_DRIVER_BRANCH " " AAC_DRIVER_BUILD_DATE +#endif MODULE_AUTHOR("Red Hat Inc and Adaptec"); MODULE_DESCRIPTION("Dell PERC2, 2/Si, 3/Si, 3/Di, " "Adaptec Advanced Raid Products, " "and HP NetRAID-4M SCSI driver"); MODULE_LICENSE("GPL"); -MODULE_VERSION(AAC_DRIVER_VERSION); +MODULE_VERSION(AAC_DRIVER_FULL_VERSION); static LIST_HEAD(aac_devices); static int aac_cfg_major = -1; +char aac_driver_version[] = AAC_DRIVER_FULL_VERSION; /* * Because of the way Linux names scsi devices, the order in this table has @@ -896,8 +907,8 @@ static int __init aac_init(void) { int error; - printk(KERN_INFO "Red Hat/Adaptec aacraid driver (%s %s)\n", - AAC_DRIVER_VERSION, AAC_DRIVER_BUILD_DATE); + printk(KERN_INFO "Adaptec %s driver (%s)\n", + AAC_DRIVERNAME, aac_driver_version); error = pci_module_init(&aac_pci_driver); if (error) From bd1aac809ddbcf7772cfd809d8cfb29c729c6cf9 Mon Sep 17 00:00:00 2001 From: Mark Haverkamp Date: Wed, 3 Aug 2005 15:39:01 -0700 Subject: [PATCH 035/114] [SCSI] aacraid: driver shutdown method Add in pci shutdown method so that the adapter shuts down correctly and flushes its cache. Shutdown should also disable the adapter's interrupt when shutdown (in particularly if the driver is rmmod'd) to prevent spurious hardware activities. Signed-off-by: Mark Haverkamp Signed-off-by: James Bottomley --- drivers/scsi/aacraid/aacraid.h | 4 ++++ drivers/scsi/aacraid/linit.c | 13 ++++++++++++- drivers/scsi/aacraid/rkt.c | 20 ++++++++++++++++++++ drivers/scsi/aacraid/rx.c | 20 ++++++++++++++++++++ drivers/scsi/aacraid/sa.c | 22 ++++++++++++++++++++-- 5 files changed, 76 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index ddbbb85b3a7c..6f4906ee9a5e 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h @@ -460,6 +460,7 @@ struct adapter_ops { void (*adapter_interrupt)(struct aac_dev *dev); void (*adapter_notify)(struct aac_dev *dev, u32 event); + void (*adapter_disable_int)(struct aac_dev *dev); int (*adapter_sync_cmd)(struct aac_dev *dev, u32 command, u32 p1, u32 p2, u32 p3, u32 p4, u32 p5, u32 p6, u32 *status, u32 *r1, u32 *r2, u32 *r3, u32 *r4); int (*adapter_check_health)(struct aac_dev *dev); }; @@ -994,6 +995,9 @@ struct aac_dev #define aac_adapter_notify(dev, event) \ (dev)->a_ops.adapter_notify(dev, event) +#define aac_adapter_disable_int(dev) \ + (dev)->a_ops.adapter_disable_int(dev) + #define aac_adapter_sync_cmd(dev, command, p1, p2, p3, p4, p5, p6, status, r1, r2, r3, r4) \ (dev)->a_ops.adapter_sync_cmd(dev, command, p1, p2, p3, p4, p5, p6, status, r1, r2, r3, r4) diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index b6dda99f5083..41255f7893d0 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -849,11 +849,12 @@ static int __devinit aac_probe_one(struct pci_dev *pdev, return 0; -out_deinit: + out_deinit: kill_proc(aac->thread_pid, SIGKILL, 0); wait_for_completion(&aac->aif_completion); aac_send_shutdown(aac); + aac_adapter_disable_int(aac); fib_map_free(aac); pci_free_consistent(aac->pdev, aac->comm_size, aac->comm_addr, aac->comm_phys); kfree(aac->queues); @@ -870,6 +871,13 @@ static int __devinit aac_probe_one(struct pci_dev *pdev, return error; } +static void aac_shutdown(struct pci_dev *dev) +{ + struct Scsi_Host *shost = pci_get_drvdata(dev); + struct aac_dev *aac = (struct aac_dev *)shost->hostdata; + aac_send_shutdown(aac); +} + static void __devexit aac_remove_one(struct pci_dev *pdev) { struct Scsi_Host *shost = pci_get_drvdata(pdev); @@ -881,6 +889,7 @@ static void __devexit aac_remove_one(struct pci_dev *pdev) wait_for_completion(&aac->aif_completion); aac_send_shutdown(aac); + aac_adapter_disable_int(aac); fib_map_free(aac); pci_free_consistent(aac->pdev, aac->comm_size, aac->comm_addr, aac->comm_phys); @@ -901,6 +910,7 @@ static struct pci_driver aac_pci_driver = { .id_table = aac_pci_tbl, .probe = aac_probe_one, .remove = __devexit_p(aac_remove_one), + .shutdown = aac_shutdown, }; static int __init aac_init(void) @@ -919,6 +929,7 @@ static int __init aac_init(void) printk(KERN_WARNING "aacraid: unable to register \"aac\" device.\n"); } + return 0; } diff --git a/drivers/scsi/aacraid/rkt.c b/drivers/scsi/aacraid/rkt.c index 7d68b7825137..557287a0b80b 100644 --- a/drivers/scsi/aacraid/rkt.c +++ b/drivers/scsi/aacraid/rkt.c @@ -87,6 +87,16 @@ static irqreturn_t aac_rkt_intr(int irq, void *dev_id, struct pt_regs *regs) return IRQ_NONE; } +/** + * aac_rkt_disable_interrupt - Disable interrupts + * @dev: Adapter + */ + +static void aac_rkt_disable_interrupt(struct aac_dev *dev) +{ + rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff); +} + /** * rkt_sync_cmd - send a command and wait * @dev: Adapter @@ -412,10 +422,19 @@ int aac_rkt_init(struct aac_dev *dev) * Fill in the function dispatch table. */ dev->a_ops.adapter_interrupt = aac_rkt_interrupt_adapter; + dev->a_ops.adapter_disable_int = aac_rkt_disable_interrupt; dev->a_ops.adapter_notify = aac_rkt_notify_adapter; dev->a_ops.adapter_sync_cmd = rkt_sync_cmd; dev->a_ops.adapter_check_health = aac_rkt_check_health; + /* + * First clear out all interrupts. Then enable the one's that we + * can handle. + */ + rkt_writeb(dev, MUnit.OIMR, 0xff); + rkt_writel(dev, MUnit.ODR, 0xffffffff); + rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb); + if (aac_init_adapter(dev) == NULL) goto error_irq; /* @@ -438,6 +457,7 @@ int aac_rkt_init(struct aac_dev *dev) kfree(dev->queues); error_irq: + rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff); free_irq(dev->scsi_host_ptr->irq, (void *)dev); error_iounmap: diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c index 1ff25f49fada..a8459faf87ca 100644 --- a/drivers/scsi/aacraid/rx.c +++ b/drivers/scsi/aacraid/rx.c @@ -87,6 +87,16 @@ static irqreturn_t aac_rx_intr(int irq, void *dev_id, struct pt_regs *regs) return IRQ_NONE; } +/** + * aac_rx_disable_interrupt - Disable interrupts + * @dev: Adapter + */ + +static void aac_rx_disable_interrupt(struct aac_dev *dev) +{ + rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff); +} + /** * rx_sync_cmd - send a command and wait * @dev: Adapter @@ -412,10 +422,19 @@ int aac_rx_init(struct aac_dev *dev) * Fill in the function dispatch table. */ dev->a_ops.adapter_interrupt = aac_rx_interrupt_adapter; + dev->a_ops.adapter_disable_int = aac_rx_disable_interrupt; dev->a_ops.adapter_notify = aac_rx_notify_adapter; dev->a_ops.adapter_sync_cmd = rx_sync_cmd; dev->a_ops.adapter_check_health = aac_rx_check_health; + /* + * First clear out all interrupts. Then enable the one's that we + * can handle. + */ + rx_writeb(dev, MUnit.OIMR, 0xff); + rx_writel(dev, MUnit.ODR, 0xffffffff); + rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb); + if (aac_init_adapter(dev) == NULL) goto error_irq; /* @@ -438,6 +457,7 @@ int aac_rx_init(struct aac_dev *dev) kfree(dev->queues); error_irq: + rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff); free_irq(dev->scsi_host_ptr->irq, (void *)dev); error_iounmap: diff --git a/drivers/scsi/aacraid/sa.c b/drivers/scsi/aacraid/sa.c index 0680249ab861..3900abc5850d 100644 --- a/drivers/scsi/aacraid/sa.c +++ b/drivers/scsi/aacraid/sa.c @@ -81,6 +81,16 @@ static irqreturn_t aac_sa_intr(int irq, void *dev_id, struct pt_regs *regs) return IRQ_NONE; } +/** + * aac_sa_disable_interrupt - disable interrupt + * @dev: Which adapter to enable. + */ + +static void aac_sa_disable_interrupt (struct aac_dev *dev) +{ + sa_writew(dev, SaDbCSR.PRISETIRQMASK, 0xffff); +} + /** * aac_sa_notify_adapter - handle adapter notification * @dev: Adapter that notification is for @@ -214,9 +224,8 @@ static int sa_sync_cmd(struct aac_dev *dev, u32 command, static void aac_sa_interrupt_adapter (struct aac_dev *dev) { - u32 ret; sa_sync_cmd(dev, BREAKPOINT_REQUEST, 0, 0, 0, 0, 0, 0, - &ret, NULL, NULL, NULL, NULL); + NULL, NULL, NULL, NULL, NULL); } /** @@ -352,10 +361,18 @@ int aac_sa_init(struct aac_dev *dev) */ dev->a_ops.adapter_interrupt = aac_sa_interrupt_adapter; + dev->a_ops.adapter_disable_int = aac_sa_disable_interrupt; dev->a_ops.adapter_notify = aac_sa_notify_adapter; dev->a_ops.adapter_sync_cmd = sa_sync_cmd; dev->a_ops.adapter_check_health = aac_sa_check_health; + /* + * First clear out all interrupts. Then enable the one's that + * we can handle. + */ + sa_writew(dev, SaDbCSR.PRISETIRQMASK, 0xffff); + sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, (PrintfReady | DOORBELL_1 | + DOORBELL_2 | DOORBELL_3 | DOORBELL_4)); if(aac_init_adapter(dev) == NULL) goto error_irq; @@ -381,6 +398,7 @@ int aac_sa_init(struct aac_dev *dev) kfree(dev->queues); error_irq: + sa_writew(dev, SaDbCSR.PRISETIRQMASK, 0xffff); free_irq(dev->scsi_host_ptr->irq, (void *)dev); error_iounmap: From e53cb35aaefb83de695e3fd305b9cfabd5bf8c86 Mon Sep 17 00:00:00 2001 From: Mark Haverkamp Date: Wed, 3 Aug 2005 15:39:09 -0700 Subject: [PATCH 036/114] [SCSI] aacraid: remove duplicate io callback code Received from Mark Salyzyn from Adaptec: This patch removes the duplicate code in the write_callback command completion handler, and renames read_callback to io_callback. Optimized the lba calculation into the debug print routine macro to optimize the i/o code path. Signed-off-by: Mark Haverkamp Signed-off-by: James Bottomley --- drivers/scsi/aacraid/aachba.c | 63 ++++------------------------------- 1 file changed, 7 insertions(+), 56 deletions(-) diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index ccdf440021fb..b03c8dee76b7 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -814,12 +814,11 @@ int aac_get_adapter_info(struct aac_dev* dev) } -static void read_callback(void *context, struct fib * fibptr) +static void io_callback(void *context, struct fib * fibptr) { struct aac_dev *dev; struct aac_read_reply *readreply; struct scsi_cmnd *scsicmd; - u32 lba; u32 cid; scsicmd = (struct scsi_cmnd *) context; @@ -827,8 +826,7 @@ static void read_callback(void *context, struct fib * fibptr) dev = (struct aac_dev *)scsicmd->device->host->hostdata; cid = ID_LUN_TO_CONTAINER(scsicmd->device->id, scsicmd->device->lun); - lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3]; - dprintk((KERN_DEBUG "read_callback[cpu %d]: lba = %u, t = %ld.\n", smp_processor_id(), lba, jiffies)); + dprintk((KERN_DEBUG "io_callback[cpu %d]: lba = %u, t = %ld.\n", smp_processor_id(), ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3], jiffies)); if (fibptr == NULL) BUG(); @@ -847,7 +845,7 @@ static void read_callback(void *context, struct fib * fibptr) scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; else { #ifdef AAC_DETAILED_STATUS_INFO - printk(KERN_WARNING "read_callback: io failed, status = %d\n", + printk(KERN_WARNING "io_callback: io failed, status = %d\n", le32_to_cpu(readreply->status)); #endif scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; @@ -867,53 +865,6 @@ static void read_callback(void *context, struct fib * fibptr) aac_io_done(scsicmd); } -static void write_callback(void *context, struct fib * fibptr) -{ - struct aac_dev *dev; - struct aac_write_reply *writereply; - struct scsi_cmnd *scsicmd; - u32 lba; - u32 cid; - - scsicmd = (struct scsi_cmnd *) context; - dev = (struct aac_dev *)scsicmd->device->host->hostdata; - cid = ID_LUN_TO_CONTAINER(scsicmd->device->id, scsicmd->device->lun); - - lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3]; - dprintk((KERN_DEBUG "write_callback[cpu %d]: lba = %u, t = %ld.\n", smp_processor_id(), lba, jiffies)); - if (fibptr == NULL) - BUG(); - - if(scsicmd->use_sg) - pci_unmap_sg(dev->pdev, - (struct scatterlist *)scsicmd->buffer, - scsicmd->use_sg, - scsicmd->sc_data_direction); - else if(scsicmd->request_bufflen) - pci_unmap_single(dev->pdev, scsicmd->SCp.dma_handle, - scsicmd->request_bufflen, - scsicmd->sc_data_direction); - - writereply = (struct aac_write_reply *) fib_data(fibptr); - if (le32_to_cpu(writereply->status) == ST_OK) - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; - else { - printk(KERN_WARNING "write_callback: write failed, status = %d\n", writereply->status); - scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; - set_sense((u8 *) &dev->fsa_dev[cid].sense_data, - HARDWARE_ERROR, - SENCODE_INTERNAL_TARGET_FAILURE, - ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0, - 0, 0); - memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, - sizeof(struct sense_data)); - } - - fib_complete(fibptr); - fib_free(fibptr); - aac_io_done(scsicmd); -} - static int aac_read(struct scsi_cmnd * scsicmd, int cid) { u32 lba; @@ -978,7 +929,7 @@ static int aac_read(struct scsi_cmnd * scsicmd, int cid) fibsize, FsaNormal, 0, 1, - (fib_callback) read_callback, + (fib_callback) io_callback, (void *) scsicmd); } else { struct aac_read *readcmd; @@ -1002,7 +953,7 @@ static int aac_read(struct scsi_cmnd * scsicmd, int cid) fibsize, FsaNormal, 0, 1, - (fib_callback) read_callback, + (fib_callback) io_callback, (void *) scsicmd); } @@ -1085,7 +1036,7 @@ static int aac_write(struct scsi_cmnd * scsicmd, int cid) fibsize, FsaNormal, 0, 1, - (fib_callback) write_callback, + (fib_callback) io_callback, (void *) scsicmd); } else { struct aac_write *writecmd; @@ -1111,7 +1062,7 @@ static int aac_write(struct scsi_cmnd * scsicmd, int cid) fibsize, FsaNormal, 0, 1, - (fib_callback) write_callback, + (fib_callback) io_callback, (void *) scsicmd); } From 12a26d0879d8a4502425037e9013b1f64ed669b7 Mon Sep 17 00:00:00 2001 From: Mark Haverkamp Date: Wed, 3 Aug 2005 15:39:25 -0700 Subject: [PATCH 037/114] [SCSI] aacraid: aif registration timeout fix Received from Mark Salyzyn from Adaptec: If the Adapter is quiet and does not produce an AIF event packets to be picked up by the management applications for longer than the timeout interval of two minutes, the cleanup code that deals with aging out registrants could erroneously drop the registration. The timeout is there to clean up should the management application die and fail to poll for updated AIF event packets. Moving the timer update from the ioctl code that delivers an AIF to the polling registrant to the bottom of the ioctl means the timeout is reset with any management application polling activity regardless if an AIF is delivered or not removing the erroneous timeout cleanups. Signed-off-by: Mark Haverkamp Signed-off-by: James Bottomley --- drivers/scsi/aacraid/commctrl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c index 8fceff9be1be..71f1cad9b5f0 100644 --- a/drivers/scsi/aacraid/commctrl.c +++ b/drivers/scsi/aacraid/commctrl.c @@ -287,7 +287,6 @@ static int next_getadapter_fib(struct aac_dev * dev, void __user *arg) kfree(fib->hw_fib); kfree(fib); status = 0; - fibctx->jiffies = jiffies/HZ; } else { spin_unlock_irqrestore(&dev->fib_lock, flags); if (f.wait) { @@ -302,6 +301,7 @@ static int next_getadapter_fib(struct aac_dev * dev, void __user *arg) status = -EAGAIN; } } + fibctx->jiffies = jiffies/HZ; return status; } From 0e68c00373f61fcdee453f6c9878e3390fc0f0ce Mon Sep 17 00:00:00 2001 From: Mark Haverkamp Date: Wed, 3 Aug 2005 15:39:49 -0700 Subject: [PATCH 038/114] [SCSI] aacraid: sgraw command support Received from Mark Salyzyn from Adaptec: This patch adds support for the new raw io command. This new command offers much larger io commands, is more friendly to the internal firmware structure requiring less translation efforts by the firmware and offers support for targets greater than 2TB (patch to support >2TB will be sent in the future). Signed-off-by: Mark Haverkamp Signed-off-by: James Bottomley --- drivers/scsi/aacraid/aachba.c | 181 +++++++++++++++++++++++++++------ drivers/scsi/aacraid/aacraid.h | 43 +++++++- 2 files changed, 194 insertions(+), 30 deletions(-) diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index b03c8dee76b7..d6c999cd7f78 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -133,6 +133,7 @@ struct inquiry_data { static unsigned long aac_build_sg(struct scsi_cmnd* scsicmd, struct sgmap* sgmap); static unsigned long aac_build_sg64(struct scsi_cmnd* scsicmd, struct sgmap64* psg); +static unsigned long aac_build_sgraw(struct scsi_cmnd* scsicmd, struct sgmapraw* psg); static int aac_send_srb_fib(struct scsi_cmnd* scsicmd); #ifdef AAC_DETAILED_STATUS_INFO static char *aac_get_status_string(u32 status); @@ -777,34 +778,36 @@ int aac_get_adapter_info(struct aac_dev* dev) /* * 57 scatter gather elements */ - dev->scsi_host_ptr->sg_tablesize = (dev->max_fib_size - - sizeof(struct aac_fibhdr) - - sizeof(struct aac_write) + sizeof(struct sgmap)) / - sizeof(struct sgmap); - if (dev->dac_support) { - /* - * 38 scatter gather elements - */ - dev->scsi_host_ptr->sg_tablesize = - (dev->max_fib_size - + if (!(dev->raw_io_interface)) { + dev->scsi_host_ptr->sg_tablesize = (dev->max_fib_size - sizeof(struct aac_fibhdr) - - sizeof(struct aac_write64) + - sizeof(struct sgmap64)) / - sizeof(struct sgmap64); - } - dev->scsi_host_ptr->max_sectors = AAC_MAX_32BIT_SGBCOUNT; - if(!(dev->adapter_info.options & AAC_OPT_NEW_COMM)) { - /* - * Worst case size that could cause sg overflow when - * we break up SG elements that are larger than 64KB. - * Would be nice if we could tell the SCSI layer what - * the maximum SG element size can be. Worst case is - * (sg_tablesize-1) 4KB elements with one 64KB - * element. - * 32bit -> 468 or 238KB 64bit -> 424 or 212KB - */ - dev->scsi_host_ptr->max_sectors = - (dev->scsi_host_ptr->sg_tablesize * 8) + 112; + sizeof(struct aac_write) + sizeof(struct sgmap)) / + sizeof(struct sgmap); + if (dev->dac_support) { + /* + * 38 scatter gather elements + */ + dev->scsi_host_ptr->sg_tablesize = + (dev->max_fib_size - + sizeof(struct aac_fibhdr) - + sizeof(struct aac_write64) + + sizeof(struct sgmap64)) / + sizeof(struct sgmap64); + } + dev->scsi_host_ptr->max_sectors = AAC_MAX_32BIT_SGBCOUNT; + if(!(dev->adapter_info.options & AAC_OPT_NEW_COMM)) { + /* + * Worst case size that could cause sg overflow when + * we break up SG elements that are larger than 64KB. + * Would be nice if we could tell the SCSI layer what + * the maximum SG element size can be. Worst case is + * (sg_tablesize-1) 4KB elements with one 64KB + * element. + * 32bit -> 468 or 238KB 64bit -> 424 or 212KB + */ + dev->scsi_host_ptr->max_sectors = + (dev->scsi_host_ptr->sg_tablesize * 8) + 112; + } } fib_complete(fibptr); @@ -905,7 +908,32 @@ static int aac_read(struct scsi_cmnd * scsicmd, int cid) fib_init(cmd_fibcontext); - if (dev->dac_support == 1) { + if (dev->raw_io_interface) { + struct aac_raw_io *readcmd; + readcmd = (struct aac_raw_io *) fib_data(cmd_fibcontext); + readcmd->block[0] = cpu_to_le32(lba); + readcmd->block[1] = 0; + readcmd->count = cpu_to_le32(count<<9); + readcmd->cid = cpu_to_le16(cid); + readcmd->flags = cpu_to_le16(1); + readcmd->bpTotal = 0; + readcmd->bpComplete = 0; + + aac_build_sgraw(scsicmd, &readcmd->sg); + fibsize = sizeof(struct aac_raw_io) + ((le32_to_cpu(readcmd->sg.count) - 1) * sizeof (struct sgentryraw)); + if (fibsize > (dev->max_fib_size - sizeof(struct aac_fibhdr))) + BUG(); + /* + * Now send the Fib to the adapter + */ + status = fib_send(ContainerRawIo, + cmd_fibcontext, + fibsize, + FsaNormal, + 0, 1, + (fib_callback) io_callback, + (void *) scsicmd); + } else if (dev->dac_support == 1) { struct aac_read64 *readcmd; readcmd = (struct aac_read64 *) fib_data(cmd_fibcontext); readcmd->command = cpu_to_le32(VM_CtHostRead64); @@ -1012,7 +1040,32 @@ static int aac_write(struct scsi_cmnd * scsicmd, int cid) } fib_init(cmd_fibcontext); - if(dev->dac_support == 1) { + if (dev->raw_io_interface) { + struct aac_raw_io *writecmd; + writecmd = (struct aac_raw_io *) fib_data(cmd_fibcontext); + writecmd->block[0] = cpu_to_le32(lba); + writecmd->block[1] = 0; + writecmd->count = cpu_to_le32(count<<9); + writecmd->cid = cpu_to_le16(cid); + writecmd->flags = 0; + writecmd->bpTotal = 0; + writecmd->bpComplete = 0; + + aac_build_sgraw(scsicmd, &writecmd->sg); + fibsize = sizeof(struct aac_raw_io) + ((le32_to_cpu(writecmd->sg.count) - 1) * sizeof (struct sgentryraw)); + if (fibsize > (dev->max_fib_size - sizeof(struct aac_fibhdr))) + BUG(); + /* + * Now send the Fib to the adapter + */ + status = fib_send(ContainerRawIo, + cmd_fibcontext, + fibsize, + FsaNormal, + 0, 1, + (fib_callback) io_callback, + (void *) scsicmd); + } else if (dev->dac_support == 1) { struct aac_write64 *writecmd; writecmd = (struct aac_write64 *) fib_data(cmd_fibcontext); writecmd->command = cpu_to_le32(VM_CtHostWrite64); @@ -2028,6 +2081,76 @@ static unsigned long aac_build_sg64(struct scsi_cmnd* scsicmd, struct sgmap64* p return byte_count; } +static unsigned long aac_build_sgraw(struct scsi_cmnd* scsicmd, struct sgmapraw* psg) +{ + struct Scsi_Host *host = scsicmd->device->host; + struct aac_dev *dev = (struct aac_dev *)host->hostdata; + unsigned long byte_count = 0; + + // Get rid of old data + psg->count = 0; + psg->sg[0].next = 0; + psg->sg[0].prev = 0; + psg->sg[0].addr[0] = 0; + psg->sg[0].addr[1] = 0; + psg->sg[0].count = 0; + psg->sg[0].flags = 0; + if (scsicmd->use_sg) { + struct scatterlist *sg; + int i; + int sg_count; + sg = (struct scatterlist *) scsicmd->request_buffer; + + sg_count = pci_map_sg(dev->pdev, sg, scsicmd->use_sg, + scsicmd->sc_data_direction); + + for (i = 0; i < sg_count; i++) { + int count = sg_dma_len(sg); + u64 addr = sg_dma_address(sg); + psg->sg[i].next = 0; + psg->sg[i].prev = 0; + psg->sg[i].addr[1] = cpu_to_le32((u32)(addr>>32)); + psg->sg[i].addr[0] = cpu_to_le32((u32)(addr & 0xffffffff)); + psg->sg[i].count = cpu_to_le32(count); + psg->sg[i].flags = 0; + byte_count += count; + sg++; + } + psg->count = cpu_to_le32(sg_count); + /* hba wants the size to be exact */ + if(byte_count > scsicmd->request_bufflen){ + u32 temp = le32_to_cpu(psg->sg[i-1].count) - + (byte_count - scsicmd->request_bufflen); + psg->sg[i-1].count = cpu_to_le32(temp); + byte_count = scsicmd->request_bufflen; + } + /* Check for command underflow */ + if(scsicmd->underflow && (byte_count < scsicmd->underflow)){ + printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n", + byte_count, scsicmd->underflow); + } + } + else if(scsicmd->request_bufflen) { + int count; + u64 addr; + scsicmd->SCp.dma_handle = pci_map_single(dev->pdev, + scsicmd->request_buffer, + scsicmd->request_bufflen, + scsicmd->sc_data_direction); + addr = scsicmd->SCp.dma_handle; + count = scsicmd->request_bufflen; + psg->count = cpu_to_le32(1); + psg->sg[0].next = 0; + psg->sg[0].prev = 0; + psg->sg[0].addr[1] = cpu_to_le32((u32)(addr>>32)); + psg->sg[0].addr[0] = cpu_to_le32((u32)(addr & 0xffffffff)); + psg->sg[0].count = cpu_to_le32(count); + psg->sg[0].flags = 0; + byte_count = scsicmd->request_bufflen; + } + return byte_count; +} + #ifdef AAC_DETAILED_STATUS_INFO struct aac_srb_status_info { diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index 6f4906ee9a5e..bc91e7ce5e59 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h @@ -114,6 +114,22 @@ struct user_sgentry64 { u32 count; /* Length. */ }; +struct sgentryraw { + __le32 next; /* reserved for F/W use */ + __le32 prev; /* reserved for F/W use */ + __le32 addr[2]; + __le32 count; + __le32 flags; /* reserved for F/W use */ +}; + +struct user_sgentryraw { + u32 next; /* reserved for F/W use */ + u32 prev; /* reserved for F/W use */ + u32 addr[2]; + u32 count; + u32 flags; /* reserved for F/W use */ +}; + /* * SGMAP * @@ -141,6 +157,16 @@ struct user_sgmap64 { struct user_sgentry64 sg[1]; }; +struct sgmapraw { + __le32 count; + struct sgentryraw sg[1]; +}; + +struct user_sgmapraw { + u32 count; + struct user_sgentryraw sg[1]; +}; + struct creation_info { u8 buildnum; /* e.g., 588 */ @@ -355,6 +381,7 @@ struct hw_fib { */ #define ContainerCommand 500 #define ContainerCommand64 501 +#define ContainerRawIo 502 /* * Cluster Commands */ @@ -986,6 +1013,9 @@ struct aac_dev u8 nondasd_support; u8 dac_support; u8 raid_scsi_mode; + /* macro side-effects BEWARE */ +# define raw_io_interface \ + init->InitStructRevision==cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION_4) u8 printf_enabled; }; @@ -1164,6 +1194,17 @@ struct aac_write_reply __le32 committed; }; +struct aac_raw_io +{ + __le32 block[2]; + __le32 count; + __le16 cid; + __le16 flags; /* 00 W, 01 R */ + __le16 bpTotal; /* reserved for F/W use */ + __le16 bpComplete; /* reserved for F/W use */ + struct sgmapraw sg; +}; + #define CT_FLUSH_CACHE 129 struct aac_synchronize { __le32 command; /* VM_ContainerConfig */ @@ -1204,7 +1245,7 @@ struct aac_srb }; /* - * This and assocated data structs are used by the + * This and associated data structs are used by the * ioctl caller and are in cpu order. */ struct user_aac_srb From a2ae85df80a5b996a05d6d2ffc9bf97797e93ec6 Mon Sep 17 00:00:00 2001 From: "akpm@osdl.org" Date: Sat, 6 Aug 2005 23:32:07 -0700 Subject: [PATCH 039/114] [SCSI] aic79xx: needs to select SPI_TRANSPORT_ATTRS without it you get this failure: drivers/built-in.o(.text+0xdcccd): In function `ahd_linux_slave_configure': drivers/scsi/aic7xxx/aic79xx_osm.c:636: undefined reference to `spi_dv_device' drivers/built-in.o(.text+0xdd7b1): In function `ahd_send_async': drivers/scsi/aic7xxx/aic79xx_osm.c:1652: undefined reference to `spi_display_xfer_agreement' drivers/built-in.o(.init.text+0x7b4d): In function `ahd_linux_init': drivers/scsi/aic7xxx/aic79xx_osm.c:2765: undefined reference to `spi_attach_transport' drivers/built-in.o(.init.text+0x7c94):drivers/scsi/aic7xxx/aic79xx_osm.c:2774: undefined reference to `spi_release_transport' drivers/built-in.o(.exit.text+0x72c): In function `ahd_linux_exit': drivers/scsi/aic7xxx/aic79xx_osm.c:2783: undefined reference to `spi_release_transport' Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/Kconfig.aic79xx | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/aic7xxx/Kconfig.aic79xx b/drivers/scsi/aic7xxx/Kconfig.aic79xx index c2523a30a7f5..69ed77fcb71f 100644 --- a/drivers/scsi/aic7xxx/Kconfig.aic79xx +++ b/drivers/scsi/aic7xxx/Kconfig.aic79xx @@ -5,6 +5,7 @@ config SCSI_AIC79XX tristate "Adaptec AIC79xx U320 support" depends on PCI && SCSI + select SCSI_SPI_ATTRS help This driver supports all of Adaptec's Ultra 320 PCI-X based SCSI controllers. From 5262d0851cc6692390ee1aa2c55f57f3bfd0a7c7 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Fri, 5 Aug 2005 16:31:35 -0500 Subject: [PATCH 040/114] [SCSI] aacraid: correct use of cmd->timeout field The cmd->timeout field has been obsolete for a while now. While looking to remove it, I came across this use in the aacraid driver. It looks like you want to initialise the firmware with the current timeout of the command (in seconds), so the value I think you should be using is cmd->timeout_per_command. Acked by: Mark Haverkamp Acked by: Mark Salyzyn Signed-off-by: James Bottomley --- drivers/scsi/aacraid/aachba.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index d6c999cd7f78..8e3493587299 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -1898,7 +1898,7 @@ static int aac_send_srb_fib(struct scsi_cmnd* scsicmd) srbcmd->id = cpu_to_le32(scsicmd->device->id); srbcmd->lun = cpu_to_le32(scsicmd->device->lun); srbcmd->flags = cpu_to_le32(flag); - timeout = (scsicmd->timeout-jiffies)/HZ; + timeout = scsicmd->timeout_per_command/HZ; if(timeout == 0){ timeout = 1; } From f03a567054fea4f9d43c50ec91338266c0bd588d Mon Sep 17 00:00:00 2001 From: Kai Makisara Date: Tue, 2 Aug 2005 13:40:47 +0300 Subject: [PATCH 041/114] [SCSI] drivers/scsi/st.c: add reference count and related fixes I have rediffed the patch against 2.6.13-rc5, done a couple of cosmetic cleanups, and run some tests. Brian King has acknowledged that it fixes the problems he has seen. Seems mature enough for inclusion into 2.6.14 (or later)? Nate's explanation of the changes: I've attached patches against 2.6.13rc2. These are basically identical to my earlier patches, as I found that all issues I'd seen in earlier kernels still existed in this kernel. To summarize, the changes are: (more details in my original email) - add a kref to the scsi_tape structure, and associate reference counting stuff - set sr_request->end_io = blk_end_sync_rq so we get notified when an IO is rejected when the device goes away - check rq_status when IOs complete, else we don't know that IOs rejected for a dead device in fact did not complete - change last_SRpnt so it's set before an async IO is issued (in case st_sleep_done is bypassed) - fix a bogus use of last_SRpnt in st_chk_result Signed-off-by: Nate Dailey Signed-off-by: Kai Makisara Signed-off-by: James Bottomley --- drivers/scsi/st.c | 150 +++++++++++++++++++++++++++++++++++++--------- drivers/scsi/st.h | 3 +- 2 files changed, 123 insertions(+), 30 deletions(-) diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 0291a8fb654d..47a5698a712a 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -17,7 +17,7 @@ Last modified: 18-JAN-1998 Richard Gooch Devfs support */ -static char *verstr = "20050501"; +static char *verstr = "20050802"; #include @@ -219,6 +219,12 @@ static int switch_partition(struct scsi_tape *); static int st_int_ioctl(struct scsi_tape *, unsigned int, unsigned long); +static void scsi_tape_release(struct kref *); + +#define to_scsi_tape(obj) container_of(obj, struct scsi_tape, kref) + +static DECLARE_MUTEX(st_ref_sem); + #include "osst_detect.h" #ifndef SIGS_FROM_OSST @@ -230,6 +236,46 @@ static int st_int_ioctl(struct scsi_tape *, unsigned int, unsigned long); {"OnStream", "FW-", "", "osst"} #endif +static struct scsi_tape *scsi_tape_get(int dev) +{ + struct scsi_tape *STp = NULL; + + down(&st_ref_sem); + write_lock(&st_dev_arr_lock); + + if (dev < st_dev_max && scsi_tapes != NULL) + STp = scsi_tapes[dev]; + if (!STp) goto out; + + kref_get(&STp->kref); + + if (!STp->device) + goto out_put; + + if (scsi_device_get(STp->device)) + goto out_put; + + goto out; + +out_put: + kref_put(&STp->kref, scsi_tape_release); + STp = NULL; +out: + write_unlock(&st_dev_arr_lock); + up(&st_ref_sem); + return STp; +} + +static void scsi_tape_put(struct scsi_tape *STp) +{ + struct scsi_device *sdev = STp->device; + + down(&st_ref_sem); + kref_put(&STp->kref, scsi_tape_release); + scsi_device_put(sdev); + up(&st_ref_sem); +} + struct st_reject_data { char *vendor; char *model; @@ -311,7 +357,7 @@ static int st_chk_result(struct scsi_tape *STp, struct scsi_request * SRpnt) return 0; cmdstatp = &STp->buffer->cmdstat; - st_analyze_sense(STp->buffer->last_SRpnt, cmdstatp); + st_analyze_sense(SRpnt, cmdstatp); if (cmdstatp->have_sense) scode = STp->buffer->cmdstat.sense_hdr.sense_key; @@ -399,10 +445,10 @@ static void st_sleep_done(struct scsi_cmnd * SCpnt) (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; ) - complete(SCpnt->request->waiting); + if (SCpnt->request->waiting) + complete(SCpnt->request->waiting); } /* Do the scsi command. Waits until command performed if do_wait is true. @@ -412,8 +458,20 @@ static struct scsi_request * st_do_scsi(struct scsi_request * SRpnt, struct scsi_tape * STp, unsigned char *cmd, int bytes, int direction, int timeout, int retries, int do_wait) { + struct completion *waiting; unsigned char *bp; + /* if async, make sure there's no command outstanding */ + if (!do_wait && ((STp->buffer)->last_SRpnt)) { + printk(KERN_ERR "%s: Async command already active.\n", + tape_name(STp)); + if (signal_pending(current)) + (STp->buffer)->syscall_result = (-EINTR); + else + (STp->buffer)->syscall_result = (-EBUSY); + return NULL; + } + if (SRpnt == NULL) { SRpnt = scsi_allocate_request(STp->device, GFP_ATOMIC); if (SRpnt == NULL) { @@ -427,7 +485,13 @@ st_do_scsi(struct scsi_request * SRpnt, struct scsi_tape * STp, unsigned char *c } } - init_completion(&STp->wait); + /* If async IO, set last_SRpnt. This ptr tells write_behind_check + which IO is outstanding. It's nulled out when the IO completes. */ + if (!do_wait) + (STp->buffer)->last_SRpnt = SRpnt; + + waiting = &STp->wait; + init_completion(waiting); SRpnt->sr_use_sg = STp->buffer->do_dio || (bytes > (STp->buffer)->frp[0].length); if (SRpnt->sr_use_sg) { if (!STp->buffer->do_dio) @@ -438,17 +502,20 @@ st_do_scsi(struct scsi_request * SRpnt, struct scsi_tape * STp, unsigned char *c bp = (STp->buffer)->b_data; SRpnt->sr_data_direction = direction; SRpnt->sr_cmd_len = 0; - SRpnt->sr_request->waiting = &(STp->wait); + SRpnt->sr_request->waiting = waiting; SRpnt->sr_request->rq_status = RQ_SCSI_BUSY; SRpnt->sr_request->rq_disk = STp->disk; + SRpnt->sr_request->end_io = blk_end_sync_rq; STp->buffer->cmdstat.have_sense = 0; scsi_do_req(SRpnt, (void *) cmd, bp, bytes, st_sleep_done, timeout, retries); if (do_wait) { - wait_for_completion(SRpnt->sr_request->waiting); + wait_for_completion(waiting); SRpnt->sr_request->waiting = NULL; + if (SRpnt->sr_request->rq_status != RQ_SCSI_DONE) + SRpnt->sr_result |= (DRIVER_ERROR << 24); (STp->buffer)->syscall_result = st_chk_result(STp, SRpnt); } return SRpnt; @@ -465,6 +532,7 @@ static int write_behind_check(struct scsi_tape * STp) struct st_buffer *STbuffer; struct st_partstat *STps; struct st_cmdstatus *cmdstatp; + struct scsi_request *SRpnt; STbuffer = STp->buffer; if (!STbuffer->writing) @@ -478,10 +546,14 @@ static int write_behind_check(struct scsi_tape * STp) ) /* end DEB */ wait_for_completion(&(STp->wait)); - (STp->buffer)->last_SRpnt->sr_request->waiting = NULL; + SRpnt = STbuffer->last_SRpnt; + STbuffer->last_SRpnt = NULL; + SRpnt->sr_request->waiting = NULL; + if (SRpnt->sr_request->rq_status != RQ_SCSI_DONE) + SRpnt->sr_result |= (DRIVER_ERROR << 24); - (STp->buffer)->syscall_result = st_chk_result(STp, (STp->buffer)->last_SRpnt); - scsi_release_request((STp->buffer)->last_SRpnt); + (STp->buffer)->syscall_result = st_chk_result(STp, SRpnt); + scsi_release_request(SRpnt); STbuffer->buffer_bytes -= STbuffer->writing; STps = &(STp->ps[STp->partition]); @@ -1055,25 +1127,20 @@ static int st_open(struct inode *inode, struct file *filp) */ filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE); + if (!(STp = scsi_tape_get(dev))) + return -ENXIO; + write_lock(&st_dev_arr_lock); - if (dev >= st_dev_max || scsi_tapes == NULL || - ((STp = scsi_tapes[dev]) == NULL)) { - write_unlock(&st_dev_arr_lock); - return (-ENXIO); - } filp->private_data = STp; name = tape_name(STp); if (STp->in_use) { write_unlock(&st_dev_arr_lock); + scsi_tape_put(STp); DEB( printk(ST_DEB_MSG "%s: Device already in use.\n", name); ) return (-EBUSY); } - if(scsi_device_get(STp->device)) { - write_unlock(&st_dev_arr_lock); - return (-ENXIO); - } STp->in_use = 1; write_unlock(&st_dev_arr_lock); STp->rew_at_close = STp->autorew_dev = (iminor(inode) & 0x80) == 0; @@ -1118,7 +1185,7 @@ static int st_open(struct inode *inode, struct file *filp) err_out: normalize_buffer(STp->buffer); STp->in_use = 0; - scsi_device_put(STp->device); + scsi_tape_put(STp); return retval; } @@ -1250,7 +1317,7 @@ static int st_release(struct inode *inode, struct file *filp) write_lock(&st_dev_arr_lock); STp->in_use = 0; write_unlock(&st_dev_arr_lock); - scsi_device_put(STp->device); + scsi_tape_put(STp); return result; } @@ -3887,6 +3954,7 @@ static int st_probe(struct device *dev) goto out_put_disk; } memset(tpnt, 0, sizeof(struct scsi_tape)); + kref_init(&tpnt->kref); tpnt->disk = disk; sprintf(disk->disk_name, "st%d", i); disk->private_data = &tpnt->driver; @@ -3902,6 +3970,7 @@ static int st_probe(struct device *dev) tpnt->tape_type = MT_ISSCSI2; tpnt->buffer = buffer; + tpnt->buffer->last_SRpnt = NULL; tpnt->inited = 0; tpnt->dirty = 0; @@ -4076,15 +4145,10 @@ static int st_remove(struct device *dev) tpnt->modes[mode].cdevs[j] = NULL; } } - tpnt->device = NULL; - if (tpnt->buffer) { - tpnt->buffer->orig_frp_segs = 0; - normalize_buffer(tpnt->buffer); - kfree(tpnt->buffer); - } - put_disk(tpnt->disk); - kfree(tpnt); + down(&st_ref_sem); + kref_put(&tpnt->kref, scsi_tape_release); + up(&st_ref_sem); return 0; } } @@ -4093,6 +4157,34 @@ static int st_remove(struct device *dev) return 0; } +/** + * scsi_tape_release - Called to free the Scsi_Tape structure + * @kref: pointer to embedded kref + * + * st_ref_sem must be held entering this routine. Because it is + * called on last put, you should always use the scsi_tape_get() + * scsi_tape_put() helpers which manipulate the semaphore directly + * and never do a direct kref_put(). + **/ +static void scsi_tape_release(struct kref *kref) +{ + struct scsi_tape *tpnt = to_scsi_tape(kref); + struct gendisk *disk = tpnt->disk; + + tpnt->device = NULL; + + if (tpnt->buffer) { + tpnt->buffer->orig_frp_segs = 0; + normalize_buffer(tpnt->buffer); + kfree(tpnt->buffer); + } + + disk->private_data = NULL; + put_disk(disk); + kfree(tpnt); + return; +} + static void st_intr(struct scsi_cmnd *SCpnt) { scsi_io_completion(SCpnt, (SCpnt->result ? 0: SCpnt->bufflen), 1); diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h index 061da111398e..790acac160bc 100644 --- a/drivers/scsi/st.h +++ b/drivers/scsi/st.h @@ -3,7 +3,7 @@ #define _ST_H #include - +#include /* Descriptor for analyzed sense data */ struct st_cmdstatus { @@ -156,6 +156,7 @@ struct scsi_tape { unsigned char last_sense[16]; #endif struct gendisk *disk; + struct kref kref; }; /* Bit masks for use_pf */ From b21a41385118f9a6af3cd96ce71090c5ada52eb5 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Fri, 5 Aug 2005 21:45:40 -0500 Subject: [PATCH 042/114] [SCSI] add global timeout to the scsi mid-layer There are certain rogue devices (and the aic7xxx driver) that return BUSY or QUEUE_FULL forever. This code will apply a global timeout (of the total number of retries times the per command timer) to a given command. If it is exceeded, the command is completed regardless of its state. The patch also removes the unused field in the command: timeout and timeout_total. This solves the problem of detecting an endless loop in the mid-layer because of BUSY/QUEUE_FULL bouncing, but will not recover the device. In the aic7xxx case, the driver can be recovered by sending a bus reset, so possibly this should be tied into the error handler? Signed-off-by: James Bottomley --- drivers/scsi/advansys.c | 4 ++-- drivers/scsi/scsi.c | 15 +++++++++++++++ include/scsi/scsi_cmnd.h | 8 ++++++-- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 0fb93363eb22..37ec5411e325 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -9200,8 +9200,8 @@ asc_prt_scsi_cmnd(struct scsi_cmnd *s) (unsigned) s->serial_number, s->retries, s->allowed); printk( -" timeout_per_command %d, timeout_total %d, timeout %d\n", - s->timeout_per_command, s->timeout_total, s->timeout); +" timeout_per_command %d\n", + s->timeout_per_command); printk( " scsi_done 0x%lx, done 0x%lx, host_scribble 0x%lx, result 0x%x\n", diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index d1aa95d45a70..4befbc275f94 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -268,6 +268,7 @@ struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, int gfp_mask) } else put_device(&dev->sdev_gendev); + cmd->jiffies_at_alloc = jiffies; return cmd; } EXPORT_SYMBOL(scsi_get_command); @@ -798,9 +799,23 @@ static void scsi_softirq(struct softirq_action *h) while (!list_empty(&local_q)) { struct scsi_cmnd *cmd = list_entry(local_q.next, struct scsi_cmnd, eh_entry); + /* The longest time any command should be outstanding is the + * per command timeout multiplied by the number of retries. + * + * For a typical command, this is 2.5 minutes */ + unsigned long wait_for + = cmd->allowed * cmd->timeout_per_command; list_del_init(&cmd->eh_entry); disposition = scsi_decide_disposition(cmd); + if (disposition != SUCCESS && + time_before(cmd->jiffies_at_alloc + wait_for, jiffies)) { + dev_printk(KERN_ERR, &cmd->device->sdev_gendev, + "timing out command, waited %ds\n", + wait_for/HZ); + disposition = SUCCESS; + } + scsi_log_completion(cmd, disposition); switch (disposition) { case SUCCESS: diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h index 9957f16dcc5d..bed4b7c9be99 100644 --- a/include/scsi/scsi_cmnd.h +++ b/include/scsi/scsi_cmnd.h @@ -51,12 +51,16 @@ struct scsi_cmnd { * printk's to use ->pid, so that we can kill this field. */ unsigned long serial_number; + /* + * This is set to jiffies as it was when the command was first + * allocated. It is used to time how long the command has + * been outstanding + */ + unsigned long jiffies_at_alloc; int retries; int allowed; int timeout_per_command; - int timeout_total; - int timeout; unsigned char cmd_len; unsigned char old_cmd_len; From 8e87c2f118d40d2dc2f5d0140818e8cd023b13e1 Mon Sep 17 00:00:00 2001 From: Mark Haverkamp Date: Mon, 8 Aug 2005 14:20:43 -0700 Subject: [PATCH 043/114] [SCSI] aacraid: adapter support update Received from Mark Salyzyn This patch adds the product ID for the ICP9067MA adapter. The entries for the ICP9085LI, ICP5085BR, IBM8k & ASR4810SAS were incorrect and would not initialize the adapters correctly. Signed-off-by: Mark Haverkamp Signed-off-by: James Bottomley --- drivers/scsi/aacraid/linit.c | 68 ++++++++++++++++++++---------------- 1 file changed, 37 insertions(+), 31 deletions(-) diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 41255f7893d0..2bd594267881 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -120,36 +120,39 @@ static struct pci_device_id aac_pci_tbl[] = { { 0x9005, 0x0286, 0x9005, 0x02a3, 0, 0, 29 }, /* ICP5085AU (Hurricane) */ { 0x9005, 0x0285, 0x9005, 0x02a4, 0, 0, 30 }, /* ICP9085LI (Marauder-X) */ { 0x9005, 0x0285, 0x9005, 0x02a5, 0, 0, 31 }, /* ICP5085BR (Marauder-E) */ - { 0x9005, 0x0287, 0x9005, 0x0800, 0, 0, 32 }, /* Themisto Jupiter Platform */ - { 0x9005, 0x0200, 0x9005, 0x0200, 0, 0, 32 }, /* Themisto Jupiter Platform */ - { 0x9005, 0x0286, 0x9005, 0x0800, 0, 0, 33 }, /* Callisto Jupiter Platform */ - { 0x9005, 0x0285, 0x9005, 0x028e, 0, 0, 34 }, /* ASR-2020SA SATA PCI-X ZCR (Skyhawk) */ - { 0x9005, 0x0285, 0x9005, 0x028f, 0, 0, 35 }, /* ASR-2025SA SATA SO-DIMM PCI-X ZCR (Terminator) */ - { 0x9005, 0x0285, 0x9005, 0x0290, 0, 0, 36 }, /* AAR-2410SA PCI SATA 4ch (Jaguar II) */ - { 0x9005, 0x0285, 0x1028, 0x0291, 0, 0, 37 }, /* CERC SATA RAID 2 PCI SATA 6ch (DellCorsair) */ - { 0x9005, 0x0285, 0x9005, 0x0292, 0, 0, 38 }, /* AAR-2810SA PCI SATA 8ch (Corsair-8) */ - { 0x9005, 0x0285, 0x9005, 0x0293, 0, 0, 39 }, /* AAR-21610SA PCI SATA 16ch (Corsair-16) */ - { 0x9005, 0x0285, 0x9005, 0x0294, 0, 0, 40 }, /* ESD SO-DIMM PCI-X SATA ZCR (Prowler) */ - { 0x9005, 0x0285, 0x103C, 0x3227, 0, 0, 41 }, /* AAR-2610SA PCI SATA 6ch */ - { 0x9005, 0x0285, 0x9005, 0x0296, 0, 0, 42 }, /* ASR-2240S (SabreExpress) */ - { 0x9005, 0x0285, 0x9005, 0x0297, 0, 0, 43 }, /* ASR-4005SAS */ - { 0x9005, 0x0285, 0x1014, 0x02F2, 0, 0, 44 }, /* IBM 8i (AvonPark) */ - { 0x9005, 0x0285, 0x1014, 0x0312, 0, 0, 44 }, /* IBM 8i (AvonPark Lite) */ - { 0x9005, 0x0285, 0x9005, 0x0298, 0, 0, 45 }, /* ASR-4000SAS (BlackBird) */ - { 0x9005, 0x0285, 0x9005, 0x0299, 0, 0, 46 }, /* ASR-4800SAS (Marauder-X) */ - { 0x9005, 0x0285, 0x9005, 0x029a, 0, 0, 47 }, /* ASR-4805SAS (Marauder-E) */ - { 0x9005, 0x0286, 0x9005, 0x02a2, 0, 0, 48 }, /* ASR-4810SAS (Hurricane */ + { 0x9005, 0x0286, 0x9005, 0x02a6, 0, 0, 32 }, /* ICP9067MA (Intruder-6) */ + { 0x9005, 0x0287, 0x9005, 0x0800, 0, 0, 33 }, /* Themisto Jupiter Platform */ + { 0x9005, 0x0200, 0x9005, 0x0200, 0, 0, 33 }, /* Themisto Jupiter Platform */ + { 0x9005, 0x0286, 0x9005, 0x0800, 0, 0, 34 }, /* Callisto Jupiter Platform */ + { 0x9005, 0x0285, 0x9005, 0x028e, 0, 0, 35 }, /* ASR-2020SA SATA PCI-X ZCR (Skyhawk) */ + { 0x9005, 0x0285, 0x9005, 0x028f, 0, 0, 36 }, /* ASR-2025SA SATA SO-DIMM PCI-X ZCR (Terminator) */ + { 0x9005, 0x0285, 0x9005, 0x0290, 0, 0, 37 }, /* AAR-2410SA PCI SATA 4ch (Jaguar II) */ + { 0x9005, 0x0285, 0x1028, 0x0291, 0, 0, 38 }, /* CERC SATA RAID 2 PCI SATA 6ch (DellCorsair) */ + { 0x9005, 0x0285, 0x9005, 0x0292, 0, 0, 39 }, /* AAR-2810SA PCI SATA 8ch (Corsair-8) */ + { 0x9005, 0x0285, 0x9005, 0x0293, 0, 0, 40 }, /* AAR-21610SA PCI SATA 16ch (Corsair-16) */ + { 0x9005, 0x0285, 0x9005, 0x0294, 0, 0, 41 }, /* ESD SO-DIMM PCI-X SATA ZCR (Prowler) */ + { 0x9005, 0x0285, 0x103C, 0x3227, 0, 0, 42 }, /* AAR-2610SA PCI SATA 6ch */ + { 0x9005, 0x0285, 0x9005, 0x0296, 0, 0, 43 }, /* ASR-2240S (SabreExpress) */ + { 0x9005, 0x0285, 0x9005, 0x0297, 0, 0, 44 }, /* ASR-4005SAS */ + { 0x9005, 0x0285, 0x1014, 0x02F2, 0, 0, 45 }, /* IBM 8i (AvonPark) */ + { 0x9005, 0x0285, 0x1014, 0x0312, 0, 0, 45 }, /* IBM 8i (AvonPark Lite) */ + { 0x9005, 0x0286, 0x1014, 0x9580, 0, 0, 46 }, /* IBM 8k/8k-l8 (Aurora) */ + { 0x9005, 0x0286, 0x1014, 0x9540, 0, 0, 47 }, /* IBM 8k/8k-l4 (Aurora Lite) */ + { 0x9005, 0x0285, 0x9005, 0x0298, 0, 0, 48 }, /* ASR-4000SAS (BlackBird) */ + { 0x9005, 0x0285, 0x9005, 0x0299, 0, 0, 49 }, /* ASR-4800SAS (Marauder-X) */ + { 0x9005, 0x0285, 0x9005, 0x029a, 0, 0, 50 }, /* ASR-4805SAS (Marauder-E) */ + { 0x9005, 0x0286, 0x9005, 0x02a2, 0, 0, 51 }, /* ASR-4810SAS (Hurricane */ - { 0x9005, 0x0285, 0x1028, 0x0287, 0, 0, 49 }, /* Perc 320/DC*/ - { 0x1011, 0x0046, 0x9005, 0x0365, 0, 0, 50 }, /* Adaptec 5400S (Mustang)*/ - { 0x1011, 0x0046, 0x9005, 0x0364, 0, 0, 51 }, /* Adaptec 5400S (Mustang)*/ - { 0x1011, 0x0046, 0x9005, 0x1364, 0, 0, 52 }, /* Dell PERC2/QC */ - { 0x1011, 0x0046, 0x103c, 0x10c2, 0, 0, 53 }, /* HP NetRAID-4M */ + { 0x9005, 0x0285, 0x1028, 0x0287, 0, 0, 52 }, /* Perc 320/DC*/ + { 0x1011, 0x0046, 0x9005, 0x0365, 0, 0, 53 }, /* Adaptec 5400S (Mustang)*/ + { 0x1011, 0x0046, 0x9005, 0x0364, 0, 0, 54 }, /* Adaptec 5400S (Mustang)*/ + { 0x1011, 0x0046, 0x9005, 0x1364, 0, 0, 55 }, /* Dell PERC2/QC */ + { 0x1011, 0x0046, 0x103c, 0x10c2, 0, 0, 56 }, /* HP NetRAID-4M */ - { 0x9005, 0x0285, 0x1028, PCI_ANY_ID, 0, 0, 54 }, /* Dell Catchall */ - { 0x9005, 0x0285, 0x17aa, PCI_ANY_ID, 0, 0, 55 }, /* Legend Catchall */ - { 0x9005, 0x0285, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 56 }, /* Adaptec Catch All */ - { 0x9005, 0x0286, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 57 }, /* Adaptec Rocket Catch All */ + { 0x9005, 0x0285, 0x1028, PCI_ANY_ID, 0, 0, 57 }, /* Dell Catchall */ + { 0x9005, 0x0285, 0x17aa, PCI_ANY_ID, 0, 0, 58 }, /* Legend Catchall */ + { 0x9005, 0x0285, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 59 }, /* Adaptec Catch All */ + { 0x9005, 0x0286, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 60 }, /* Adaptec Rocket Catch All */ { 0,} }; MODULE_DEVICE_TABLE(pci, aac_pci_tbl); @@ -191,8 +194,9 @@ static struct aac_driver_ident aac_drivers[] = { { aac_rkt_init, "aacraid", "ICP ", "ICP9047MA ", 1 }, /* ICP9047MA (Lancer) */ { aac_rkt_init, "aacraid", "ICP ", "ICP9087MA ", 1 }, /* ICP9087MA (Lancer) */ { aac_rkt_init, "aacraid", "ICP ", "ICP5085AU ", 1 }, /* ICP5085AU (Hurricane) */ - { aac_rkt_init, "aacraid", "ICP ", "ICP9085LI ", 1 }, /* ICP9085LI (Marauder-X) */ - { aac_rkt_init, "aacraid", "ICP ", "ICP5085BR ", 1 }, /* ICP5085BR (Marauder-E) */ + { aac_rx_init, "aacraid", "ICP ", "ICP9085LI ", 1 }, /* ICP9085LI (Marauder-X) */ + { aac_rx_init, "aacraid", "ICP ", "ICP5085BR ", 1 }, /* ICP5085BR (Marauder-E) */ + { aac_rkt_init, "aacraid", "ICP ", "ICP9067MA ", 1 }, /* ICP9067MA (Intruder-6) */ { NULL , "aacraid", "ADAPTEC ", "Themisto ", 0, AAC_QUIRK_SLAVE }, /* Jupiter Platform */ { aac_rkt_init, "aacraid", "ADAPTEC ", "Callisto ", 2, AAC_QUIRK_MASTER }, /* Jupiter Platform */ { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2020SA ", 1 }, /* ASR-2020SA SATA PCI-X ZCR (Skyhawk) */ @@ -206,10 +210,12 @@ static struct aac_driver_ident aac_drivers[] = { { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-2240S ", 1 }, /* ASR-2240S (SabreExpress) */ { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4005SAS ", 1 }, /* ASR-4005SAS */ { aac_rx_init, "ServeRAID","IBM ", "ServeRAID 8i ", 1 }, /* IBM 8i (AvonPark) */ + { aac_rkt_init, "ServeRAID","IBM ", "ServeRAID 8k-l8 ", 1 }, /* IBM 8k/8k-l8 (Aurora) */ + { aac_rkt_init, "ServeRAID","IBM ", "ServeRAID 8k-l4 ", 1 }, /* IBM 8k/8k-l4 (Aurora Lite) */ { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4000SAS ", 1 }, /* ASR-4000SAS (BlackBird & AvonPark) */ { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4800SAS ", 1 }, /* ASR-4800SAS (Marauder-X) */ { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4805SAS ", 1 }, /* ASR-4805SAS (Marauder-E) */ - { aac_rx_init, "aacraid", "ADAPTEC ", "ASR-4810SAS ", 1 }, /* ASR-4810SAS (Hurricane) */ + { aac_rkt_init, "aacraid", "ADAPTEC ", "ASR-4810SAS ", 1 }, /* ASR-4810SAS (Hurricane) */ { aac_rx_init, "percraid", "DELL ", "PERC 320/DC ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Perc 320/DC*/ { aac_sa_init, "aacraid", "ADAPTEC ", "Adaptec 5400S ", 4, AAC_QUIRK_34SG }, /* Adaptec 5400S (Mustang)*/ From 0d7323c865608dffb1ed39ec2f3841697ec3e009 Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Mon, 8 Aug 2005 19:01:43 -0400 Subject: [PATCH 044/114] [SCSI] blacklist addition. When run on a kernel that scans all LUNs, a certain crappy scsi scanner reports the same LUN over and over.. https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=155457 Aparently they were so shamed by this, they chose to remain anonymous. Though it seems the blacklist code handles anonymous vendors just fine. Signed-off-by: Dave Jones Signed-off-by: James Bottomley --- drivers/scsi/scsi_devinfo.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index 6121dc1bfada..d9963a848d94 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -114,6 +114,7 @@ static struct { {"YAMAHA", "CDR102", "1.00", BLIST_NOLUN}, /* locks up */ {"YAMAHA", "CRW8424S", "1.0", BLIST_NOLUN}, /* locks up */ {"YAMAHA", "CRW6416S", "1.0c", BLIST_NOLUN}, /* locks up */ + {"", "Scanner", "1.80", BLIST_NOLUN}, /* responds to all lun */ /* * Other types of devices that have special flags. From a80b3424d9fde3c4b6d62adaf6dda78128dc5c27 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Mon, 8 Aug 2005 19:06:50 -0500 Subject: [PATCH 045/114] [SCSI] aic79xx: fix boot panic with no hardware There's a spurious (and illegal since it's marked __exit) call to ahc_linux_exit() in ahc_linux_init() which causes a double list deletion of the transport class; remove it. Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic79xx_osm.c | 4 +--- drivers/scsi/aic7xxx/aic7xxx_osm.c | 2 -- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index acaeebd50465..2f158624c5d2 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -2326,8 +2326,6 @@ ahd_linux_queue_recovery_cmd(struct scsi_cmnd *cmd, scb_flag flag) return (retval); } -static void ahd_linux_exit(void); - static void ahd_linux_set_width(struct scsi_target *starget, int width) { struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); @@ -2772,7 +2770,7 @@ ahd_linux_init(void) if (ahd_linux_detect(&aic79xx_driver_template) > 0) return 0; spi_release_transport(ahd_linux_transport_template); - ahd_linux_exit(); + return -ENODEV; } diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index 3fbc10e58cc2..22434849de48 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -2335,8 +2335,6 @@ ahc_platform_dump_card_state(struct ahc_softc *ahc) { } -static void ahc_linux_exit(void); - static void ahc_linux_set_width(struct scsi_target *starget, int width) { struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); From 507caac75e86bd041c5462e5e988fb7138e21d79 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Tue, 9 Aug 2005 12:57:11 -0500 Subject: [PATCH 046/114] [SCSI] Make the HSG80 a REPORTLUN2 device From: Steve Wilcox In order to properly report LUN's > 7, the DEC HSG80 definition in scsi_devinfo.c needs to include BLIST_REPORTLUN2 rather than BLIST_SPARSELUN. I've tested this change with several HSG firmware revisions and with both Emulex and Qlogic HBA's. Signed-off-by: James Bottomley --- drivers/scsi/scsi_devinfo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index d9963a848d94..b444ec2e1c64 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -136,7 +136,7 @@ static struct { {"COMPAQ", "MSA1000 VOLUME", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD}, {"COMPAQ", "HSV110", NULL, BLIST_REPORTLUN2 | BLIST_NOSTARTONADD}, {"DDN", "SAN DataDirector", "*", BLIST_SPARSELUN}, - {"DEC", "HSG80", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD}, + {"DEC", "HSG80", NULL, BLIST_REPORTLUN2 | BLIST_NOSTARTONADD}, {"DELL", "PV660F", NULL, BLIST_SPARSELUN}, {"DELL", "PV660F PSEUDO", NULL, BLIST_SPARSELUN}, {"DELL", "PSEUDO DEVICE .", NULL, BLIST_SPARSELUN}, /* Dell PV 530F */ From 483f05f0134e60b724bc3678507c1def860c56d5 Mon Sep 17 00:00:00 2001 From: "James.Smart@Emulex.Com" Date: Wed, 10 Aug 2005 15:02:45 -0400 Subject: [PATCH 047/114] [SCSI] lpfc driver 8.0.30 : fix iocb reuse initialization IOCB BDE not getting fully initialized during reuse Symptoms: Driver gets Status 3 and Reason 0x13 on IOCB completions. Cause: The IOCB bpl.bdeSize and bdeFlags are not getting initialized on reuse. Fix: Reinitialize these fields in prep_dma each time an IOCB is used. Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_scsi.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 17e4974d4445..7cb1e467734f 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -238,6 +238,8 @@ lpfc_scsi_prep_dma_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * lpfc_cmd) bpl->tus.f.bdeSize = scsi_cmnd->request_bufflen; if (datadir == DMA_TO_DEVICE) bpl->tus.f.bdeFlags = 0; + else + bpl->tus.f.bdeFlags = BUFF_USE_RCV; bpl->tus.w = le32_to_cpu(bpl->tus.w); num_bde = 1; bpl++; @@ -245,8 +247,11 @@ lpfc_scsi_prep_dma_buf(struct lpfc_hba * phba, struct lpfc_scsi_buf * lpfc_cmd) /* * Finish initializing those IOCB fields that are dependent on the - * scsi_cmnd request_buffer + * scsi_cmnd request_buffer. Note that the bdeSize is explicitly + * reinitialized since all iocb memory resources are used many times + * for transmit, receive, and continuation bpl's. */ + iocb_cmd->un.fcpi64.bdl.bdeSize = (2 * sizeof (struct ulp_bde64)); iocb_cmd->un.fcpi64.bdl.bdeSize += (num_bde * sizeof (struct ulp_bde64)); iocb_cmd->ulpBdeCount = 1; From 8cbdc5fffa15d5c573e2531c6f533822d08b6b0f Mon Sep 17 00:00:00 2001 From: "James.Smart@Emulex.Com" Date: Wed, 10 Aug 2005 15:02:50 -0400 Subject: [PATCH 048/114] [SCSI] lpfc driver 8.0.30 : fix lip/cablepull panic Fix panic on lip and cable pull Symptoms: Panic on lip or cable pull Cause: Use after free of nlp in lpfc_nlp_remove() Fix: Do not make FC transport calls after a node is removed. Transport calls are disabled by ignoring the initial delete transition. Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_hbadisc.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 233901e9dfde..2e44824a3bd5 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1135,6 +1135,8 @@ lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list) switch(list) { case NLP_NO_LIST: /* No list, just remove it */ lpfc_nlp_remove(phba, nlp); + /* as node removed - stop further transport calls */ + rport_del = none; break; case NLP_UNUSED_LIST: spin_lock_irq(phba->host->host_lock); From 69859dc47744430ecda16522b0791b6d17e3fa93 Mon Sep 17 00:00:00 2001 From: "James.Smart@Emulex.Com" Date: Wed, 10 Aug 2005 15:02:37 -0400 Subject: [PATCH 049/114] [SCSI] lpfc driver 8.0.30 : task mgmt bit clearing Clear task management bits when preparing SCSI commands In lpfc_scsi_prep_cmnd, clear the task management bits (fcpCntl2 member in the fcp_cmd structure) when preparing regular SCSI commands. Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_scsi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 7cb1e467734f..15e747faaa5f 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -450,6 +450,8 @@ lpfc_scsi_prep_cmnd(struct lpfc_hba * phba, struct lpfc_scsi_buf * lpfc_cmd, int datadir = scsi_cmnd->sc_data_direction; lpfc_cmd->fcp_rsp->rspSnsLen = 0; + /* clear task management bits */ + lpfc_cmd->fcp_cmnd->fcpCntl2 = 0; lpfc_put_lun(lpfc_cmd->fcp_cmnd, lpfc_cmd->pCmd->device->lun); From f888ba3ce77c66bece3d804caf7d559838209a4a Mon Sep 17 00:00:00 2001 From: "James.Smart@Emulex.Com" Date: Wed, 10 Aug 2005 15:03:01 -0400 Subject: [PATCH 050/114] [SCSI] lpfc driver 8.0.30 : fix get_stats panic Fix panic in lpfc_get_stats() Symptoms: Panic on sysfs stats access Cause: In lpfc_get_stats() we are writing to memory that we do not own. Fix: Fix our stats structure allocation. Embed phba->link_stats in struct lpfc_hba and stop treating it like rogue structure. Note: Embedding midlayer/transport structure in our structure caused need for more files to include midlayer/transport headers. Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc.h | 5 ++--- drivers/scsi/lpfc/lpfc_attr.c | 5 +++-- drivers/scsi/lpfc/lpfc_ct.c | 1 + drivers/scsi/lpfc/lpfc_init.c | 4 +--- drivers/scsi/lpfc/lpfc_mbox.c | 3 +++ drivers/scsi/lpfc/lpfc_mem.c | 3 +++ drivers/scsi/lpfc/lpfc_sli.c | 1 + 7 files changed, 14 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 3bb82aae432e..adb95674823f 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -342,9 +342,6 @@ struct lpfc_hba { #define VPD_MASK 0xf /* mask for any vpd data */ struct timer_list els_tmofunc; - - void *link_stats; - /* * stat counters */ @@ -370,6 +367,8 @@ struct lpfc_hba { struct list_head freebufList; struct list_head ctrspbuflist; struct list_head rnidrspbuflist; + + struct fc_host_statistics link_stats; }; diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 3cea92883019..f37b7642c59d 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -988,8 +988,7 @@ lpfc_get_stats(struct Scsi_Host *shost) { struct lpfc_hba *phba = (struct lpfc_hba *)shost->hostdata[0]; struct lpfc_sli *psli = &phba->sli; - struct fc_host_statistics *hs = - (struct fc_host_statistics *)phba->link_stats; + struct fc_host_statistics *hs = &phba->link_stats; LPFC_MBOXQ_t *pmboxq; MAILBOX_t *pmb; int rc=0; @@ -1020,6 +1019,8 @@ lpfc_get_stats(struct Scsi_Host *shost) return NULL; } + memset(hs, 0, sizeof (struct fc_host_statistics)); + hs->tx_frames = pmb->un.varRdStatus.xmitFrameCnt; hs->tx_words = (pmb->un.varRdStatus.xmitByteCnt * 256); hs->rx_frames = pmb->un.varRdStatus.rcvFrameCnt; diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index 78adee4699af..b3880eca2f3c 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -29,6 +29,7 @@ #include #include +#include #include "lpfc_hw.h" #include "lpfc_sli.h" diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 34d416d2b007..1b6d1dcdabb3 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1339,14 +1339,12 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid) if (pci_request_regions(pdev, LPFC_DRIVER_NAME)) goto out_disable_device; - host = scsi_host_alloc(&lpfc_template, - sizeof (struct lpfc_hba) + sizeof (unsigned long)); + host = scsi_host_alloc(&lpfc_template, sizeof (struct lpfc_hba)); if (!host) goto out_release_regions; phba = (struct lpfc_hba*)host->hostdata; memset(phba, 0, sizeof (struct lpfc_hba)); - phba->link_stats = (void *)&phba[1]; phba->host = host; phba->fc_flag |= FC_LOADING; diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index c27cf94795db..afcd54d51f16 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -23,6 +23,9 @@ #include #include +#include +#include + #include "lpfc_hw.h" #include "lpfc_sli.h" #include "lpfc_disc.h" diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c index a5cfb6421fa9..034a8bfa9ac8 100644 --- a/drivers/scsi/lpfc/lpfc_mem.c +++ b/drivers/scsi/lpfc/lpfc_mem.c @@ -23,6 +23,9 @@ #include #include +#include +#include + #include "lpfc_hw.h" #include "lpfc_sli.h" #include "lpfc_disc.h" diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 1775508ed276..e027f4708103 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "lpfc_hw.h" #include "lpfc_sli.h" From ea84c3f74df646a0897e95c78147190517a751a9 Mon Sep 17 00:00:00 2001 From: "James.Smart@Emulex.Com" Date: Wed, 10 Aug 2005 15:02:30 -0400 Subject: [PATCH 051/114] [SCSI] lpfc driver 8.0.30 : dev_loss and nodev timeouts Fix handling of the dev_loss and nodev timeouts. Symptoms: when remote port disappears for a period of time longer then either nodev_tmo or dev_loss_tmo, the lpfc driver worker thread will stall removing that remote port. Cause: removing remote port involves un-blocking and sync-ing corresponding block device queue. But corresponding node in the lpfc driver is still in the NPR(?node port recovery?) state and mid-layer gets SCSI_MLQUEUE_HOST_BUSY as a return value when it is trying to call queuecommand() with command for that node (AKA remote port) Fix: Instead of returning SCSI_MLQUEUE_HOST_BUS from queuecommand() for nodes in NPR states complete it with retry-able error code DID_BUS_BUSY Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_scsi.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 15e747faaa5f..4be506a33a2e 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -753,6 +753,10 @@ lpfc_queuecommand(struct scsi_cmnd *cmnd, void (*done) (struct scsi_cmnd *)) cmnd->result = ScsiResult(DID_NO_CONNECT, 0); goto out_fail_command; } + else if (ndlp->nlp_state == NLP_STE_NPR_NODE) { + cmnd->result = ScsiResult(DID_BUS_BUSY, 0); + goto out_fail_command; + } /* * The device is most likely recovered and the driver * needs a bit more time to finish. Ask the midlayer From 918865230e55b1fece2d8edec39d46c00626590b Mon Sep 17 00:00:00 2001 From: "James.Smart@Emulex.Com" Date: Wed, 10 Aug 2005 15:03:09 -0400 Subject: [PATCH 052/114] [SCSI] lpfc driver 8.0.30 : convert to use of int_to_scsilun() Replace use of lpfc_put_lun with midlayer's int_to_scsilun Remove driver's local definition of lpfc_put_lun (which converts an int back to a 64-bit LUN) and replace it's use with the recently added int_to_scsilun function provided by the midlayer. Note: Embedding midlayer structure in our structure caused need for more files to include midlayer headers. Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_attr.c | 1 + drivers/scsi/lpfc/lpfc_ct.c | 1 + drivers/scsi/lpfc/lpfc_els.c | 1 + drivers/scsi/lpfc/lpfc_hbadisc.c | 1 + drivers/scsi/lpfc/lpfc_init.c | 1 + drivers/scsi/lpfc/lpfc_mbox.c | 2 ++ drivers/scsi/lpfc/lpfc_mem.c | 2 ++ drivers/scsi/lpfc/lpfc_nportdisc.c | 1 + drivers/scsi/lpfc/lpfc_scsi.c | 11 ++++------- drivers/scsi/lpfc/lpfc_scsi.h | 13 +------------ drivers/scsi/lpfc/lpfc_sli.c | 1 + 11 files changed, 16 insertions(+), 19 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index f37b7642c59d..0e089a42c03a 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -23,6 +23,7 @@ #include #include +#include #include #include #include diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index b3880eca2f3c..1280f0e54636 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -27,6 +27,7 @@ #include #include +#include #include #include #include diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 2b1c9572dae7..63caf7fe9725 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -23,6 +23,7 @@ #include #include +#include #include #include #include diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 2e44824a3bd5..0a8269d6b130 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -24,6 +24,7 @@ #include #include +#include #include #include #include diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 1b6d1dcdabb3..6f3cb59bf9e0 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -28,6 +28,7 @@ #include #include +#include #include #include #include diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index afcd54d51f16..73eb89f91593 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -26,6 +26,8 @@ #include #include +#include + #include "lpfc_hw.h" #include "lpfc_sli.h" #include "lpfc_disc.h" diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c index 034a8bfa9ac8..0aba13ceaacf 100644 --- a/drivers/scsi/lpfc/lpfc_mem.c +++ b/drivers/scsi/lpfc/lpfc_mem.c @@ -26,6 +26,8 @@ #include #include +#include + #include "lpfc_hw.h" #include "lpfc_sli.h" #include "lpfc_disc.h" diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 45dc0210fc49..9b35eaac781d 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -23,6 +23,7 @@ #include #include +#include #include #include #include diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 4be506a33a2e..b5ad1871d34b 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -40,11 +40,6 @@ #define LPFC_RESET_WAIT 2 #define LPFC_ABORT_WAIT 2 -static inline void lpfc_put_lun(struct fcp_cmnd *fcmd, unsigned int lun) -{ - fcmd->fcpLunLsl = 0; - fcmd->fcpLunMsl = swab16((uint16_t)lun); -} /* * This routine allocates a scsi buffer, which contains all the necessary @@ -453,7 +448,8 @@ lpfc_scsi_prep_cmnd(struct lpfc_hba * phba, struct lpfc_scsi_buf * lpfc_cmd, /* clear task management bits */ lpfc_cmd->fcp_cmnd->fcpCntl2 = 0; - lpfc_put_lun(lpfc_cmd->fcp_cmnd, lpfc_cmd->pCmd->device->lun); + int_to_scsilun(lpfc_cmd->pCmd->device->lun, + &lpfc_cmd->fcp_cmnd->fcp_lun); memcpy(&fcp_cmnd->fcpCdb[0], scsi_cmnd->cmnd, 16); @@ -552,7 +548,8 @@ lpfc_scsi_prep_task_mgmt_cmd(struct lpfc_hba *phba, piocb = &piocbq->iocb; fcp_cmnd = lpfc_cmd->fcp_cmnd; - lpfc_put_lun(lpfc_cmd->fcp_cmnd, lpfc_cmd->pCmd->device->lun); + int_to_scsilun(lpfc_cmd->pCmd->device->lun, + &lpfc_cmd->fcp_cmnd->fcp_lun); fcp_cmnd->fcpCntl2 = task_mgmt_cmd; piocb->ulpCommand = CMD_FCP_ICMND64_CR; diff --git a/drivers/scsi/lpfc/lpfc_scsi.h b/drivers/scsi/lpfc/lpfc_scsi.h index 0fd9ba14e1b5..acd64c49e849 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.h +++ b/drivers/scsi/lpfc/lpfc_scsi.h @@ -78,18 +78,7 @@ struct fcp_rsp { }; struct fcp_cmnd { - uint32_t fcpLunMsl; /* most significant lun word (32 bits) */ - uint32_t fcpLunLsl; /* least significant lun word (32 bits) */ - /* # of bits to shift lun id to end up in right - * payload word, little endian = 8, big = 16. - */ -#ifdef __BIG_ENDIAN -#define FC_LUN_SHIFT 16 -#define FC_ADDR_MODE_SHIFT 24 -#else /* __LITTLE_ENDIAN */ -#define FC_LUN_SHIFT 8 -#define FC_ADDR_MODE_SHIFT 0 -#endif + struct scsi_lun fcp_lun; uint8_t fcpCntl0; /* FCP_CNTL byte 0 (reserved) */ uint8_t fcpCntl1; /* FCP_CNTL byte 1 task codes */ diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index e027f4708103..e74e224fd77c 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -24,6 +24,7 @@ #include #include +#include #include #include #include From 9909b79e3d533b422c6c72945da35aef124dbce1 Mon Sep 17 00:00:00 2001 From: "James.Smart@Emulex.Com" Date: Wed, 10 Aug 2005 15:03:17 -0400 Subject: [PATCH 053/114] [SCSI] lpfc driver 8.0.30 : update version to 8.0.30 Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 47dea48ee0ec..7e6747b06f90 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -18,7 +18,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "8.0.29" +#define LPFC_DRIVER_VERSION "8.0.30" #define LPFC_DRIVER_NAME "lpfc" From 3a1c1d446b7cac6ddd8f6b1f3254ccffe87f1751 Mon Sep 17 00:00:00 2001 From: "James.Smart@Emulex.Com" Date: Thu, 11 Aug 2005 13:42:35 -0400 Subject: [PATCH 054/114] [SCSI] Add Emulex as maintainer of lpfc SCSI driver Signed-off-by: James Bottomley --- MAINTAINERS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index ec8433c39dee..562441d67b82 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -824,6 +824,13 @@ L: emu10k1-devel@lists.sourceforge.net W: http://sourceforge.net/projects/emu10k1/ S: Maintained +EMULEX LPFC FC SCSI DRIVER +P: James Smart +M: james.smart@emulex.com +L: linux-scsi@vger.kernel.org +W: http://sourceforge.net/projects/lpfcxxxx +S: Supported + EPSON 1355 FRAMEBUFFER DRIVER P: Christopher Hoover M: ch@murgatroid.com, ch@hpl.hp.com From 6becdff3bcaff1b89c392cf0630dcb5759704492 Mon Sep 17 00:00:00 2001 From: "akpm@osdl.org" Date: Tue, 9 Aug 2005 00:17:03 -0700 Subject: [PATCH 055/114] [SCSI] fix warning in scsi_softirq From: Andrew Morton drivers/scsi/scsi.c: In function `scsi_softirq': drivers/scsi/scsi.c:814: warning: int format, long int arg (arg 4) Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/scsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 4befbc275f94..a780546eda9c 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -811,7 +811,7 @@ static void scsi_softirq(struct softirq_action *h) if (disposition != SUCCESS && time_before(cmd->jiffies_at_alloc + wait_for, jiffies)) { dev_printk(KERN_ERR, &cmd->device->sdev_gendev, - "timing out command, waited %ds\n", + "timing out command, waited %lus\n", wait_for/HZ); disposition = SUCCESS; } From 0336ee5aed1f9a5a6a04e3deabd7797dc193ccd3 Mon Sep 17 00:00:00 2001 From: "akpm@osdl.org" Date: Mon, 8 Aug 2005 21:49:48 -0700 Subject: [PATCH 056/114] [SCSI] fix warning in aic7770.c From: "Martin J. Bligh" drivers/scsi/aic7xxx/aic7770.c: In function `aic7770_config': drivers/scsi/aic7xxx/aic7770.c:129: warning: unused variable `l' Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic7770.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/scsi/aic7xxx/aic7770.c b/drivers/scsi/aic7xxx/aic7770.c index 00f3bd1e181e..527efd36f5c1 100644 --- a/drivers/scsi/aic7xxx/aic7770.c +++ b/drivers/scsi/aic7xxx/aic7770.c @@ -126,7 +126,6 @@ aic7770_find_device(uint32_t id) int aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry, u_int io) { - u_long l; int error; int have_seeprom; u_int hostconf; From 3a4f5c60dbe1978580ea03c1aff353d1e63d1638 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sat, 13 Aug 2005 09:42:45 -0500 Subject: [PATCH 057/114] [SCSI] aic7xxx: lost multifunction flags handling From: Christoph Hellwig Multi-function cards need to inherit the PCI flags from the master PCI device. Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic7xxx_osm_pci.c | 29 ++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c index 9d318ce2c993..0d44a6907dd2 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c @@ -149,6 +149,27 @@ ahc_linux_pci_dev_remove(struct pci_dev *pdev) ahc_free(ahc); } +static void +ahc_linux_pci_inherit_flags(struct ahc_softc *ahc) +{ + struct pci_dev *pdev = ahc->dev_softc, *master_pdev; + unsigned int master_devfn = PCI_DEVFN(PCI_SLOT(pdev->devfn), 0); + + master_pdev = pci_get_slot(pdev->bus, master_devfn); + if (master_pdev) { + struct ahc_softc *master = pci_get_drvdata(master_pdev); + if (master) { + ahc->flags &= ~AHC_BIOS_ENABLED; + ahc->flags |= master->flags & AHC_BIOS_ENABLED; + + ahc->flags &= ~AHC_PRIMARY_CHANNEL; + ahc->flags |= master->flags & AHC_PRIMARY_CHANNEL; + } else + printk(KERN_ERR "aic7xxx: no multichannel peer found!\n"); + pci_dev_put(master_pdev); + } +} + static int ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -203,6 +224,14 @@ ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ahc_free(ahc); return (-error); } + + /* + * Second Function PCI devices need to inherit some + * settings from function 0. + */ + if ((ahc->features & AHC_MULTI_FUNC) && PCI_FUNC(pdev->devfn) != 0) + ahc_linux_pci_inherit_flags(ahc); + pci_set_drvdata(pdev, ahc); ahc_linux_register_host(ahc, &aic7xxx_driver_template); return (0); From 10c1b88987d618f4f89c10e11e574c76de73b5e7 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sun, 14 Aug 2005 14:34:06 -0500 Subject: [PATCH 058/114] [SCSI] add ability to deny binding to SPI transport class This patch is necessary if we begin exposing underlying physical disks (which can attach to the SPI transport class) of the hardware RAID cards, since we don't want any SPI parameters binding to the RAID devices. Signed-off-by: James Bottomley --- drivers/scsi/scsi_transport_spi.c | 11 ++++++++++- include/scsi/scsi_transport_spi.h | 1 + 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c index e7b9570c818b..02134fce2174 100644 --- a/drivers/scsi/scsi_transport_spi.c +++ b/drivers/scsi/scsi_transport_spi.c @@ -1082,6 +1082,7 @@ static int spi_device_match(struct attribute_container *cont, { struct scsi_device *sdev; struct Scsi_Host *shost; + struct spi_internal *i; if (!scsi_is_sdev_device(dev)) return 0; @@ -1094,6 +1095,9 @@ static int spi_device_match(struct attribute_container *cont, /* Note: this class has no device attributes, so it has * no per-HBA allocation and thus we don't need to distinguish * the attribute containers for the device */ + i = to_spi_internal(shost->transportt); + if (i->f->deny_binding && i->f->deny_binding(sdev->sdev_target)) + return 0; return 1; } @@ -1101,6 +1105,7 @@ static int spi_target_match(struct attribute_container *cont, struct device *dev) { struct Scsi_Host *shost; + struct scsi_target *starget; struct spi_internal *i; if (!scsi_is_target_device(dev)) @@ -1112,7 +1117,11 @@ static int spi_target_match(struct attribute_container *cont, return 0; i = to_spi_internal(shost->transportt); - + starget = to_scsi_target(dev); + + if (i->f->deny_binding && i->f->deny_binding(starget)) + return 0; + return &i->t.target_attrs.ac == cont; } diff --git a/include/scsi/scsi_transport_spi.h b/include/scsi/scsi_transport_spi.h index d8ef86006e02..6bdc4afb2483 100644 --- a/include/scsi/scsi_transport_spi.h +++ b/include/scsi/scsi_transport_spi.h @@ -120,6 +120,7 @@ struct spi_function_template { void (*set_hold_mcs)(struct scsi_target *, int); void (*get_signalling)(struct Scsi_Host *); void (*set_signalling)(struct Scsi_Host *, enum spi_signal_type); + int (*deny_binding)(struct scsi_target *); /* The driver sets these to tell the transport class it * wants the attributes displayed in sysfs. If the show_ flag * is not set, the attribute will be private to the transport From d0a7e574007fd547d72ec693bfa35778623d0738 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sun, 14 Aug 2005 17:09:01 -0500 Subject: [PATCH 059/114] [SCSI] correct transport class abstraction to work outside SCSI I recently tried to construct a totally generic transport class and found there were certain features missing from the current abstract transport class. Most notable is that you have to hang the data on the class_device but most of the API is framed in terms of the generic device, not the class_device. These changes are two fold - Provide the class_device to all of the setup and configure APIs - Provide and extra API to take the device and the attribute class and return the corresponding class_device Signed-off-by: James Bottomley --- drivers/base/attribute_container.c | 38 +++++++++++++++++++++++++++++ drivers/base/transport_class.c | 17 ++++++++----- drivers/scsi/scsi_transport_fc.c | 6 +++-- drivers/scsi/scsi_transport_spi.c | 11 ++++++--- include/linux/attribute_container.h | 9 +++---- include/linux/transport_class.h | 11 ++++++--- 6 files changed, 72 insertions(+), 20 deletions(-) diff --git a/drivers/base/attribute_container.c b/drivers/base/attribute_container.c index ec615d854be9..62c093db11e6 100644 --- a/drivers/base/attribute_container.c +++ b/drivers/base/attribute_container.c @@ -58,6 +58,7 @@ attribute_container_register(struct attribute_container *cont) { INIT_LIST_HEAD(&cont->node); INIT_LIST_HEAD(&cont->containers); + spin_lock_init(&cont->containers_lock); down(&attribute_container_mutex); list_add_tail(&cont->node, &attribute_container_list); @@ -77,11 +78,13 @@ attribute_container_unregister(struct attribute_container *cont) { int retval = -EBUSY; down(&attribute_container_mutex); + spin_lock(&cont->containers_lock); if (!list_empty(&cont->containers)) goto out; retval = 0; list_del(&cont->node); out: + spin_unlock(&cont->containers_lock); up(&attribute_container_mutex); return retval; @@ -151,7 +154,9 @@ attribute_container_add_device(struct device *dev, fn(cont, dev, &ic->classdev); else attribute_container_add_class_device(&ic->classdev); + spin_lock(&cont->containers_lock); list_add_tail(&ic->node, &cont->containers); + spin_unlock(&cont->containers_lock); } up(&attribute_container_mutex); } @@ -189,6 +194,7 @@ attribute_container_remove_device(struct device *dev, if (!cont->match(cont, dev)) continue; + spin_lock(&cont->containers_lock); list_for_each_entry_safe(ic, tmp, &cont->containers, node) { if (dev != ic->classdev.dev) continue; @@ -200,6 +206,7 @@ attribute_container_remove_device(struct device *dev, class_device_unregister(&ic->classdev); } } + spin_unlock(&cont->containers_lock); } up(&attribute_container_mutex); } @@ -230,10 +237,12 @@ attribute_container_device_trigger(struct device *dev, if (!cont->match(cont, dev)) continue; + spin_lock(&cont->containers_lock); list_for_each_entry_safe(ic, tmp, &cont->containers, node) { if (dev == ic->classdev.dev) fn(cont, dev, &ic->classdev); } + spin_unlock(&cont->containers_lock); } up(&attribute_container_mutex); } @@ -368,6 +377,35 @@ attribute_container_class_device_del(struct class_device *classdev) } EXPORT_SYMBOL_GPL(attribute_container_class_device_del); +/** + * attribute_container_find_class_device - find the corresponding class_device + * + * @cont: the container + * @dev: the generic device + * + * Looks up the device in the container's list of class devices and returns + * the corresponding class_device. + */ +struct class_device * +attribute_container_find_class_device(struct attribute_container *cont, + struct device *dev) +{ + struct class_device *cdev = NULL; + struct internal_container *ic; + + spin_lock(&cont->containers_lock); + list_for_each_entry(ic, &cont->containers, node) { + if (ic->classdev.dev == dev) { + cdev = &ic->classdev; + break; + } + } + spin_unlock(&cont->containers_lock); + + return cdev; +} +EXPORT_SYMBOL_GPL(attribute_container_find_class_device); + int __init attribute_container_init(void) { diff --git a/drivers/base/transport_class.c b/drivers/base/transport_class.c index 6c2b447a3336..4fb4c5de8470 100644 --- a/drivers/base/transport_class.c +++ b/drivers/base/transport_class.c @@ -64,7 +64,9 @@ void transport_class_unregister(struct transport_class *tclass) } EXPORT_SYMBOL_GPL(transport_class_unregister); -static int anon_transport_dummy_function(struct device *dev) +static int anon_transport_dummy_function(struct transport_container *tc, + struct device *dev, + struct class_device *cdev) { /* do nothing */ return 0; @@ -115,9 +117,10 @@ static int transport_setup_classdev(struct attribute_container *cont, struct class_device *classdev) { struct transport_class *tclass = class_to_transport_class(cont->class); + struct transport_container *tcont = attribute_container_to_transport_container(cont); if (tclass->setup) - tclass->setup(dev); + tclass->setup(tcont, dev, classdev); return 0; } @@ -178,12 +181,14 @@ void transport_add_device(struct device *dev) EXPORT_SYMBOL_GPL(transport_add_device); static int transport_configure(struct attribute_container *cont, - struct device *dev) + struct device *dev, + struct class_device *cdev) { struct transport_class *tclass = class_to_transport_class(cont->class); + struct transport_container *tcont = attribute_container_to_transport_container(cont); if (tclass->configure) - tclass->configure(dev); + tclass->configure(tcont, dev, cdev); return 0; } @@ -202,7 +207,7 @@ static int transport_configure(struct attribute_container *cont, */ void transport_configure_device(struct device *dev) { - attribute_container_trigger(dev, transport_configure); + attribute_container_device_trigger(dev, transport_configure); } EXPORT_SYMBOL_GPL(transport_configure_device); @@ -215,7 +220,7 @@ static int transport_remove_classdev(struct attribute_container *cont, struct transport_class *tclass = class_to_transport_class(cont->class); if (tclass->remove) - tclass->remove(dev); + tclass->remove(tcont, dev, classdev); if (tclass->remove != anon_transport_dummy_function) { if (tcont->statistics) diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index 35d1c1e8e345..96243c7fe110 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -252,7 +252,8 @@ struct fc_internal { #define to_fc_internal(tmpl) container_of(tmpl, struct fc_internal, t) -static int fc_target_setup(struct device *dev) +static int fc_target_setup(struct transport_container *tc, struct device *dev, + struct class_device *cdev) { struct scsi_target *starget = to_scsi_target(dev); struct fc_rport *rport = starget_to_rport(starget); @@ -281,7 +282,8 @@ static DECLARE_TRANSPORT_CLASS(fc_transport_class, NULL, NULL); -static int fc_host_setup(struct device *dev) +static int fc_host_setup(struct transport_container *tc, struct device *dev, + struct class_device *cdev) { struct Scsi_Host *shost = dev_to_shost(dev); diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c index 02134fce2174..89f6b7feb9c2 100644 --- a/drivers/scsi/scsi_transport_spi.c +++ b/drivers/scsi/scsi_transport_spi.c @@ -162,7 +162,8 @@ static inline enum spi_signal_type spi_signal_to_value(const char *name) return SPI_SIGNAL_UNKNOWN; } -static int spi_host_setup(struct device *dev) +static int spi_host_setup(struct transport_container *tc, struct device *dev, + struct class_device *cdev) { struct Scsi_Host *shost = dev_to_shost(dev); @@ -196,7 +197,9 @@ static int spi_host_match(struct attribute_container *cont, return &i->t.host_attrs.ac == cont; } -static int spi_device_configure(struct device *dev) +static int spi_device_configure(struct transport_container *tc, + struct device *dev, + struct class_device *cdev) { struct scsi_device *sdev = to_scsi_device(dev); struct scsi_target *starget = sdev->sdev_target; @@ -214,7 +217,9 @@ static int spi_device_configure(struct device *dev) return 0; } -static int spi_setup_transport_attrs(struct device *dev) +static int spi_setup_transport_attrs(struct transport_container *tc, + struct device *dev, + struct class_device *cdev) { struct scsi_target *starget = to_scsi_target(dev); diff --git a/include/linux/attribute_container.h b/include/linux/attribute_container.h index af1010b6dab7..f54b05b052b3 100644 --- a/include/linux/attribute_container.h +++ b/include/linux/attribute_container.h @@ -11,10 +11,12 @@ #include #include +#include struct attribute_container { struct list_head node; struct list_head containers; + spinlock_t containers_lock; struct class *class; struct class_device_attribute **attrs; int (*match)(struct attribute_container *, struct device *); @@ -62,12 +64,7 @@ int attribute_container_add_class_device_adapter(struct attribute_container *con struct class_device *classdev); void attribute_container_remove_attrs(struct class_device *classdev); void attribute_container_class_device_del(struct class_device *classdev); - - - - - - +struct class_device *attribute_container_find_class_device(struct attribute_container *, struct device *); struct class_device_attribute **attribute_container_classdev_to_attrs(const struct class_device *classdev); #endif diff --git a/include/linux/transport_class.h b/include/linux/transport_class.h index 87d98d1faefb..1d6cc22e5f42 100644 --- a/include/linux/transport_class.h +++ b/include/linux/transport_class.h @@ -12,11 +12,16 @@ #include #include +struct transport_container; + struct transport_class { struct class class; - int (*setup)(struct device *); - int (*configure)(struct device *); - int (*remove)(struct device *); + int (*setup)(struct transport_container *, struct device *, + struct class_device *); + int (*configure)(struct transport_container *, struct device *, + struct class_device *); + int (*remove)(struct transport_container *, struct device *, + struct class_device *); }; #define DECLARE_TRANSPORT_CLASS(cls, nm, su, rm, cfg) \ From d46b1d549e1414d673e0ec18219f4f5e30d5f3f5 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 15 Aug 2005 13:27:39 +0200 Subject: [PATCH 060/114] [SCSI] aic79xx: remove some dead code remove some dead cruft, as done already in aic7xxx Signed-off-by: Christoph Hellwig Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic79xx_osm.h | 35 -------------------------- drivers/scsi/aic7xxx/aic79xx_osm_pci.c | 3 --- 2 files changed, 38 deletions(-) diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h index 46edcf3e4e62..296d3a59efe9 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.h +++ b/drivers/scsi/aic7xxx/aic79xx_osm.h @@ -254,39 +254,8 @@ ahd_scb_timer_reset(struct scb *scb, u_int usec) /***************************** SMP support ************************************/ #include -#define AHD_SCSI_HAS_HOST_LOCK 1 - #define AIC79XX_DRIVER_VERSION "1.3.11" -/**************************** Front End Queues ********************************/ -/* - * Data structure used to cast the Linux struct scsi_cmnd to something - * that allows us to use the queue macros. The linux structure has - * plenty of space to hold the links fields as required by the queue - * macros, but the queue macors require them to have the correct type. - */ -struct ahd_cmd_internal { - /* Area owned by the Linux scsi layer. */ - uint8_t private[offsetof(struct scsi_cmnd, SCp.Status)]; - union { - STAILQ_ENTRY(ahd_cmd) ste; - LIST_ENTRY(ahd_cmd) le; - TAILQ_ENTRY(ahd_cmd) tqe; - } links; - uint32_t end; -}; - -struct ahd_cmd { - union { - struct ahd_cmd_internal icmd; - struct scsi_cmnd scsi_cmd; - } un; -}; - -#define acmd_icmd(cmd) ((cmd)->un.icmd) -#define acmd_scsi_cmd(cmd) ((cmd)->un.scsi_cmd) -#define acmd_links un.icmd.links - /*************************** Device Data Structures ***************************/ /* * A per probed device structure used to deal with some error recovery @@ -297,13 +266,10 @@ struct ahd_cmd { */ typedef enum { - AHD_DEV_UNCONFIGURED = 0x01, AHD_DEV_FREEZE_TIL_EMPTY = 0x02, /* Freeze queue until active == 0 */ - AHD_DEV_TIMER_ACTIVE = 0x04, /* Our timer is active */ AHD_DEV_Q_BASIC = 0x10, /* Allow basic device queuing */ AHD_DEV_Q_TAGGED = 0x20, /* Allow full SCSI2 command queueing */ AHD_DEV_PERIODIC_OTAG = 0x40, /* Send OTAG to prevent starvation */ - AHD_DEV_SLAVE_CONFIGURED = 0x80 /* slave_configure() has been called */ } ahd_linux_dev_flags; struct ahd_linux_target; @@ -432,7 +398,6 @@ struct ahd_platform_data { uint32_t irq; /* IRQ for this adapter */ uint32_t bios_address; uint32_t mem_busaddr; /* Mem Base Addr */ - uint64_t hw_dma_mask; #define AHD_SCB_UP_EH_SEM 0x1 uint32_t flags; }; diff --git a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c index 91daf0c7fb10..7cfb2eb2b868 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c @@ -177,15 +177,12 @@ ahd_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (memsize >= 0x8000000000ULL && pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0) { ahd->flags |= AHD_64BIT_ADDRESSING; - ahd->platform_data->hw_dma_mask = DMA_64BIT_MASK; } else if (memsize > 0x80000000 && pci_set_dma_mask(pdev, mask_39bit) == 0) { ahd->flags |= AHD_39BIT_ADDRESSING; - ahd->platform_data->hw_dma_mask = mask_39bit; } } else { pci_set_dma_mask(pdev, DMA_32BIT_MASK); - ahd->platform_data->hw_dma_mask = DMA_32BIT_MASK; } ahd->dev_softc = pci; error = ahd_pci_config(ahd, entry); From 85a46523ff68aa0e4d2477c51075ffd9fc7e7a14 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 15 Aug 2005 13:28:46 +0200 Subject: [PATCH 061/114] [SCSI] aic79xx: sane pci probing remove ahd_tailq and do sane pci probing. ported over from aic7xxx. Signed-off-by: Christoph Hellwig Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic79xx.h | 6 -- drivers/scsi/aic7xxx/aic79xx_core.c | 103 +---------------------- drivers/scsi/aic7xxx/aic79xx_osm.c | 108 +++++-------------------- drivers/scsi/aic7xxx/aic79xx_osm.h | 30 ------- drivers/scsi/aic7xxx/aic79xx_osm_pci.c | 77 ++++++++---------- drivers/scsi/aic7xxx/aic79xx_pci.c | 14 +--- drivers/scsi/aic7xxx/aic79xx_proc.c | 11 +-- 7 files changed, 59 insertions(+), 290 deletions(-) diff --git a/drivers/scsi/aic7xxx/aic79xx.h b/drivers/scsi/aic7xxx/aic79xx.h index fd4b2f3eb0c2..653fb0b42aea 100644 --- a/drivers/scsi/aic7xxx/aic79xx.h +++ b/drivers/scsi/aic7xxx/aic79xx.h @@ -1247,9 +1247,6 @@ struct ahd_softc { uint16_t user_tagenable;/* Tagged Queuing allowed */ }; -TAILQ_HEAD(ahd_softc_tailq, ahd_softc); -extern struct ahd_softc_tailq ahd_tailq; - /*************************** IO Cell Configuration ****************************/ #define AHD_PRECOMP_SLEW_INDEX \ (AHD_ANNEXCOL_PRECOMP_SLEW - AHD_ANNEXCOL_PER_DEV0) @@ -1374,8 +1371,6 @@ void ahd_enable_coalescing(struct ahd_softc *ahd, void ahd_pause_and_flushwork(struct ahd_softc *ahd); int ahd_suspend(struct ahd_softc *ahd); int ahd_resume(struct ahd_softc *ahd); -void ahd_softc_insert(struct ahd_softc *); -struct ahd_softc *ahd_find_softc(struct ahd_softc *ahd); void ahd_set_unit(struct ahd_softc *, int); void ahd_set_name(struct ahd_softc *, char *); struct scb *ahd_get_scb(struct ahd_softc *ahd, u_int col_idx); @@ -1524,7 +1519,6 @@ void ahd_print_scb(struct scb *scb); void ahd_print_devinfo(struct ahd_softc *ahd, struct ahd_devinfo *devinfo); void ahd_dump_sglist(struct scb *scb); -void ahd_dump_all_cards_state(void); void ahd_dump_card_state(struct ahd_softc *ahd); int ahd_print_register(ahd_reg_parse_entry_t *table, u_int num_entries, diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c index d69bbffb34a0..4e8f00df978d 100644 --- a/drivers/scsi/aic7xxx/aic79xx_core.c +++ b/drivers/scsi/aic7xxx/aic79xx_core.c @@ -52,8 +52,6 @@ #include #endif -/******************************** Globals *************************************/ -struct ahd_softc_tailq ahd_tailq = TAILQ_HEAD_INITIALIZER(ahd_tailq); /***************************** Lookup Tables **********************************/ char *ahd_chip_names[] = @@ -5179,74 +5177,6 @@ ahd_softc_init(struct ahd_softc *ahd) return (0); } -void -ahd_softc_insert(struct ahd_softc *ahd) -{ - struct ahd_softc *list_ahd; - -#if AHD_PCI_CONFIG > 0 - /* - * Second Function PCI devices need to inherit some - * settings from function 0. - */ - if ((ahd->features & AHD_MULTI_FUNC) != 0) { - TAILQ_FOREACH(list_ahd, &ahd_tailq, links) { - ahd_dev_softc_t list_pci; - ahd_dev_softc_t pci; - - list_pci = list_ahd->dev_softc; - pci = ahd->dev_softc; - if (ahd_get_pci_slot(list_pci) == ahd_get_pci_slot(pci) - && ahd_get_pci_bus(list_pci) == ahd_get_pci_bus(pci)) { - struct ahd_softc *master; - struct ahd_softc *slave; - - if (ahd_get_pci_function(list_pci) == 0) { - master = list_ahd; - slave = ahd; - } else { - master = ahd; - slave = list_ahd; - } - slave->flags &= ~AHD_BIOS_ENABLED; - slave->flags |= - master->flags & AHD_BIOS_ENABLED; - break; - } - } - } -#endif - - /* - * Insertion sort into our list of softcs. - */ - list_ahd = TAILQ_FIRST(&ahd_tailq); - while (list_ahd != NULL - && ahd_softc_comp(ahd, list_ahd) <= 0) - list_ahd = TAILQ_NEXT(list_ahd, links); - if (list_ahd != NULL) - TAILQ_INSERT_BEFORE(list_ahd, ahd, links); - else - TAILQ_INSERT_TAIL(&ahd_tailq, ahd, links); - ahd->init_level++; -} - -/* - * Verify that the passed in softc pointer is for a - * controller that is still configured. - */ -struct ahd_softc * -ahd_find_softc(struct ahd_softc *ahd) -{ - struct ahd_softc *list_ahd; - - TAILQ_FOREACH(list_ahd, &ahd_tailq, links) { - if (list_ahd == ahd) - return (ahd); - } - return (NULL); -} - void ahd_set_unit(struct ahd_softc *ahd, int unit) { @@ -7902,18 +7832,10 @@ ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset) static void ahd_reset_poll(void *arg) { - struct ahd_softc *ahd; + struct ahd_softc *ahd = arg; u_int scsiseq1; - u_long l; u_long s; - ahd_list_lock(&l); - ahd = ahd_find_softc((struct ahd_softc *)arg); - if (ahd == NULL) { - printf("ahd_reset_poll: Instance %p no longer exists\n", arg); - ahd_list_unlock(&l); - return; - } ahd_lock(ahd, &s); ahd_pause(ahd); ahd_update_modes(ahd); @@ -7924,7 +7846,6 @@ ahd_reset_poll(void *arg) ahd_reset_poll, ahd); ahd_unpause(ahd); ahd_unlock(ahd, &s); - ahd_list_unlock(&l); return; } @@ -7936,25 +7857,16 @@ ahd_reset_poll(void *arg) ahd->flags &= ~AHD_RESET_POLL_ACTIVE; ahd_unlock(ahd, &s); ahd_release_simq(ahd); - ahd_list_unlock(&l); } /**************************** Statistics Processing ***************************/ static void ahd_stat_timer(void *arg) { - struct ahd_softc *ahd; - u_long l; + struct ahd_softc *ahd = arg; u_long s; int enint_coal; - ahd_list_lock(&l); - ahd = ahd_find_softc((struct ahd_softc *)arg); - if (ahd == NULL) { - printf("ahd_stat_timer: Instance %p no longer exists\n", arg); - ahd_list_unlock(&l); - return; - } ahd_lock(ahd, &s); enint_coal = ahd->hs_mailbox & ENINT_COALESCE; @@ -7981,7 +7893,6 @@ ahd_stat_timer(void *arg) ahd_timer_reset(&ahd->stat_timer, AHD_STAT_UPDATE_US, ahd_stat_timer, ahd); ahd_unlock(ahd, &s); - ahd_list_unlock(&l); } /****************************** Status Processing *****************************/ @@ -8745,16 +8656,6 @@ ahd_probe_stack_size(struct ahd_softc *ahd) return (last_probe); } -void -ahd_dump_all_cards_state(void) -{ - struct ahd_softc *list_ahd; - - TAILQ_FOREACH(list_ahd, &ahd_tailq, links) { - ahd_dump_card_state(list_ahd); - } -} - int ahd_print_register(ahd_reg_parse_entry_t *table, u_int num_entries, const char *name, u_int address, u_int value, diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index 2f158624c5d2..3feb739cd554 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -59,11 +59,6 @@ static struct scsi_transport_template *ahd_linux_transport_template = NULL; #include /* For block_size() */ #include /* For ssleep/msleep */ -/* - * Lock protecting manipulation of the ahd softc list. - */ -spinlock_t ahd_list_spinlock; - /* * Bucket size for counting good commands in between bad ones. */ @@ -302,13 +297,6 @@ static uint32_t aic79xx_pci_parity = ~0; */ uint32_t aic79xx_allow_memio = ~0; -/* - * aic79xx_detect() has been run, so register all device arrivals - * immediately with the system rather than deferring to the sorted - * attachment performed by aic79xx_detect(). - */ -int aic79xx_detect_complete; - /* * So that we can set how long each device is given as a selection timeout. * The table of values goes like this: @@ -387,7 +375,9 @@ static void ahd_linux_setup_tag_info_global(char *p); static aic_option_callback_t ahd_linux_setup_tag_info; static aic_option_callback_t ahd_linux_setup_iocell_info; static int aic79xx_setup(char *c); -static int ahd_linux_next_unit(void); + +static int ahd_linux_unit; + /****************************** Inlines ***************************************/ static __inline void ahd_linux_unmap_scb(struct ahd_softc*, struct scb*); @@ -417,50 +407,6 @@ ahd_linux_unmap_scb(struct ahd_softc *ahd, struct scb *scb) #define BUILD_SCSIID(ahd, cmd) \ ((((cmd)->device->id << TID_SHIFT) & TID) | (ahd)->our_id) -/* - * Try to detect an Adaptec 79XX controller. - */ -static int -ahd_linux_detect(struct scsi_host_template *template) -{ - struct ahd_softc *ahd; - int found; - int error = 0; - - /* - * If we've been passed any parameters, process them now. - */ - if (aic79xx) - aic79xx_setup(aic79xx); - - template->proc_name = "aic79xx"; - - /* - * Initialize our softc list lock prior to - * probing for any adapters. - */ - ahd_list_lockinit(); - -#ifdef CONFIG_PCI - error = ahd_linux_pci_init(); - if (error) - return error; -#endif - - /* - * Register with the SCSI layer all - * controllers we've found. - */ - found = 0; - TAILQ_FOREACH(ahd, &ahd_tailq, links) { - - if (ahd_linux_register_host(ahd, template) == 0) - found++; - } - aic79xx_detect_complete++; - return found; -} - /* * Return a string describing the driver. */ @@ -760,6 +706,7 @@ ahd_linux_bus_reset(struct scsi_cmnd *cmd) struct scsi_host_template aic79xx_driver_template = { .module = THIS_MODULE, .name = "aic79xx", + .proc_name = "aic79xx", .proc_info = ahd_linux_proc_info, .info = ahd_linux_info, .queuecommand = ahd_linux_queue, @@ -1072,7 +1019,7 @@ ahd_linux_register_host(struct ahd_softc *ahd, struct scsi_host_template *templa host->max_lun = AHD_NUM_LUNS; host->max_channel = 0; host->sg_tablesize = AHD_NSEG; - ahd_set_unit(ahd, ahd_linux_next_unit()); + ahd_set_unit(ahd, ahd_linux_unit++); sprintf(buf, "scsi%d", host->host_no); new_name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT); if (new_name != NULL) { @@ -1100,29 +1047,6 @@ ahd_linux_get_memsize(void) return ((uint64_t)si.totalram << PAGE_SHIFT); } -/* - * Find the smallest available unit number to use - * for a new device. We don't just use a static - * count to handle the "repeated hot-(un)plug" - * scenario. - */ -static int -ahd_linux_next_unit(void) -{ - struct ahd_softc *ahd; - int unit; - - unit = 0; -retry: - TAILQ_FOREACH(ahd, &ahd_tailq, links) { - if (ahd->unit == unit) { - unit++; - goto retry; - } - } - return (unit); -} - /* * Place the SCSI bus into a known state by either resetting it, * or forcing transfer negotiations on the next command to any @@ -2755,23 +2679,31 @@ static struct spi_function_template ahd_linux_transport_functions = { .show_hold_mcs = 1, }; - - static int __init ahd_linux_init(void) { - ahd_linux_transport_template = spi_attach_transport(&ahd_linux_transport_functions); + int error = 0; + + /* + * If we've been passed any parameters, process them now. + */ + if (aic79xx) + aic79xx_setup(aic79xx); + + ahd_linux_transport_template = + spi_attach_transport(&ahd_linux_transport_functions); if (!ahd_linux_transport_template) return -ENODEV; + scsi_transport_reserve_target(ahd_linux_transport_template, sizeof(struct ahd_linux_target)); scsi_transport_reserve_device(ahd_linux_transport_template, sizeof(struct ahd_linux_device)); - if (ahd_linux_detect(&aic79xx_driver_template) > 0) - return 0; - spi_release_transport(ahd_linux_transport_template); - return -ENODEV; + error = ahd_linux_pci_init(); + if (error) + spi_release_transport(ahd_linux_transport_template); + return error; } static void __exit diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h index 296d3a59efe9..052c6619accc 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.h +++ b/drivers/scsi/aic7xxx/aic79xx_osm.h @@ -120,7 +120,6 @@ typedef struct scsi_cmnd *ahd_io_ctx_t; /************************* Configuration Data *********************************/ extern uint32_t aic79xx_allow_memio; -extern int aic79xx_detect_complete; extern struct scsi_host_template aic79xx_driver_template; /***************************** Bus Space/DMA **********************************/ @@ -532,17 +531,6 @@ void ahd_format_transinfo(struct info_str *info, struct ahd_transinfo *tinfo); /******************************** Locking *************************************/ -/* Lock protecting internal data structures */ -static __inline void ahd_lockinit(struct ahd_softc *); -static __inline void ahd_lock(struct ahd_softc *, unsigned long *flags); -static __inline void ahd_unlock(struct ahd_softc *, unsigned long *flags); - -/* Lock held during ahd_list manipulation and ahd softc frees */ -extern spinlock_t ahd_list_spinlock; -static __inline void ahd_list_lockinit(void); -static __inline void ahd_list_lock(unsigned long *flags); -static __inline void ahd_list_unlock(unsigned long *flags); - static __inline void ahd_lockinit(struct ahd_softc *ahd) { @@ -561,24 +549,6 @@ ahd_unlock(struct ahd_softc *ahd, unsigned long *flags) spin_unlock_irqrestore(&ahd->platform_data->spin_lock, *flags); } -static __inline void -ahd_list_lockinit(void) -{ - spin_lock_init(&ahd_list_spinlock); -} - -static __inline void -ahd_list_lock(unsigned long *flags) -{ - spin_lock_irqsave(&ahd_list_spinlock, *flags); -} - -static __inline void -ahd_list_unlock(unsigned long *flags) -{ - spin_unlock_irqrestore(&ahd_list_spinlock, *flags); -} - /******************************* PCI Definitions ******************************/ /* * PCIM_xxx: mask to locate subfield in register diff --git a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c index 7cfb2eb2b868..390b53852d4b 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c @@ -92,27 +92,31 @@ struct pci_driver aic79xx_pci_driver = { static void ahd_linux_pci_dev_remove(struct pci_dev *pdev) { - struct ahd_softc *ahd; - u_long l; + struct ahd_softc *ahd = pci_get_drvdata(pdev); + u_long s; - /* - * We should be able to just perform - * the free directly, but check our - * list for extra sanity. - */ - ahd_list_lock(&l); - ahd = ahd_find_softc((struct ahd_softc *)pci_get_drvdata(pdev)); - if (ahd != NULL) { - u_long s; + ahd_lock(ahd, &s); + ahd_intr_enable(ahd, FALSE); + ahd_unlock(ahd, &s); + ahd_free(ahd); +} - TAILQ_REMOVE(&ahd_tailq, ahd, links); - ahd_list_unlock(&l); - ahd_lock(ahd, &s); - ahd_intr_enable(ahd, FALSE); - ahd_unlock(ahd, &s); - ahd_free(ahd); - } else - ahd_list_unlock(&l); +static void +ahd_linux_pci_inherit_flags(struct ahd_softc *ahd) +{ + struct pci_dev *pdev = ahd->dev_softc, *master_pdev; + unsigned int master_devfn = PCI_DEVFN(PCI_SLOT(pdev->devfn), 0); + + master_pdev = pci_get_slot(pdev->bus, master_devfn); + if (master_pdev) { + struct ahd_softc *master = pci_get_drvdata(master_pdev); + if (master) { + ahd->flags &= ~AHD_BIOS_ENABLED; + ahd->flags |= master->flags & AHD_BIOS_ENABLED; + } else + printk(KERN_ERR "aic79xx: no multichannel peer found!\n"); + pci_dev_put(master_pdev); + } } static int @@ -125,22 +129,6 @@ ahd_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) char *name; int error; - /* - * Some BIOSen report the same device multiple times. - */ - TAILQ_FOREACH(ahd, &ahd_tailq, links) { - struct pci_dev *probed_pdev; - - probed_pdev = ahd->dev_softc; - if (probed_pdev->bus->number == pdev->bus->number - && probed_pdev->devfn == pdev->devfn) - break; - } - if (ahd != NULL) { - /* Skip duplicate. */ - return (-ENODEV); - } - pci = pdev; entry = ahd_find_pci_device(pci); if (entry == NULL) @@ -190,16 +178,17 @@ ahd_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ahd_free(ahd); return (-error); } + + /* + * Second Function PCI devices need to inherit some + * * settings from function 0. + */ + if ((ahd->features & AHD_MULTI_FUNC) && PCI_FUNC(pdev->devfn) != 0) + ahd_linux_pci_inherit_flags(ahd); + pci_set_drvdata(pdev, ahd); - if (aic79xx_detect_complete) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) - ahd_linux_register_host(ahd, &aic79xx_driver_template); -#else - printf("aic79xx: ignoring PCI device found after " - "initialization\n"); - return (-ENODEV); -#endif - } + + ahd_linux_register_host(ahd, &aic79xx_driver_template); return (0); } diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.c b/drivers/scsi/aic7xxx/aic79xx_pci.c index 703f6e44889d..2131db60018a 100644 --- a/drivers/scsi/aic7xxx/aic79xx_pci.c +++ b/drivers/scsi/aic7xxx/aic79xx_pci.c @@ -283,7 +283,6 @@ int ahd_pci_config(struct ahd_softc *ahd, struct ahd_pci_identity *entry) { struct scb_data *shared_scb_data; - u_long l; u_int command; uint32_t devconfig; uint16_t subvendor; @@ -373,16 +372,9 @@ ahd_pci_config(struct ahd_softc *ahd, struct ahd_pci_identity *entry) * Allow interrupts now that we are completely setup. */ error = ahd_pci_map_int(ahd); - if (error != 0) - return (error); - - ahd_list_lock(&l); - /* - * Link this softc in with all other ahd instances. - */ - ahd_softc_insert(ahd); - ahd_list_unlock(&l); - return (0); + if (!error) + ahd->init_level++; + return error; } /* diff --git a/drivers/scsi/aic7xxx/aic79xx_proc.c b/drivers/scsi/aic7xxx/aic79xx_proc.c index cffdd104f9e4..32be1f55998c 100644 --- a/drivers/scsi/aic7xxx/aic79xx_proc.c +++ b/drivers/scsi/aic7xxx/aic79xx_proc.c @@ -285,21 +285,13 @@ int ahd_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start, off_t offset, int length, int inout) { - struct ahd_softc *ahd; + struct ahd_softc *ahd = *(struct ahd_softc **)shost->hostdata; struct info_str info; char ahd_info[256]; - u_long l; u_int max_targ; u_int i; int retval; - retval = -EINVAL; - ahd_list_lock(&l); - ahd = ahd_find_softc(*(struct ahd_softc **)shost->hostdata); - - if (ahd == NULL) - goto done; - /* Has data been written to the file? */ if (inout == TRUE) { retval = ahd_proc_write_seeprom(ahd, buffer, length); @@ -349,6 +341,5 @@ ahd_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start, } retval = info.pos > info.offset ? info.pos - info.offset : 0; done: - ahd_list_unlock(&l); return (retval); } From 975f24bdc7d3833875309509abbc7da2b2a28234 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 15 Aug 2005 13:29:55 +0200 Subject: [PATCH 062/114] [SCSI] aiclib remove dead remove lots of completely dead code from aiclib, there's not a lot left and even what's left is rather useless. Signed-off-by: Christoph Hellwig Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aiclib.c | 1256 --------------------------------- drivers/scsi/aic7xxx/aiclib.h | 868 ----------------------- 2 files changed, 2124 deletions(-) diff --git a/drivers/scsi/aic7xxx/aiclib.c b/drivers/scsi/aic7xxx/aiclib.c index 7c5a6db0e672..4d44a9211185 100644 --- a/drivers/scsi/aic7xxx/aiclib.c +++ b/drivers/scsi/aic7xxx/aiclib.c @@ -30,1162 +30,8 @@ * $Id$ */ -#include -#include -#include - -/* Core SCSI definitions */ -#include #include "aiclib.h" -#include "cam.h" -#ifndef FALSE -#define FALSE 0 -#endif /* FALSE */ -#ifndef TRUE -#define TRUE 1 -#endif /* TRUE */ -#ifndef ERESTART -#define ERESTART -1 /* restart syscall */ -#endif -#ifndef EJUSTRETURN -#define EJUSTRETURN -2 /* don't modify regs, just return */ -#endif - -static int ascentrycomp(const void *key, const void *member); -static int senseentrycomp(const void *key, const void *member); -static void fetchtableentries(int sense_key, int asc, int ascq, - struct scsi_inquiry_data *, - const struct sense_key_table_entry **, - const struct asc_table_entry **); -static void * scsibsearch(const void *key, const void *base, size_t nmemb, - size_t size, - int (*compar)(const void *, const void *)); -typedef int (cam_quirkmatch_t)(caddr_t, caddr_t); -static int cam_strmatch(const u_int8_t *str, const u_int8_t *pattern, - int str_len); -static caddr_t cam_quirkmatch(caddr_t target, caddr_t quirk_table, - int num_entries, int entry_size, - cam_quirkmatch_t *comp_func); - -#define SCSI_NO_SENSE_STRINGS 1 -#if !defined(SCSI_NO_SENSE_STRINGS) -#define SST(asc, ascq, action, desc) \ - asc, ascq, action, desc -#else -static const char empty_string[] = ""; - -#define SST(asc, ascq, action, desc) \ - asc, ascq, action, empty_string -#endif - -static const struct sense_key_table_entry sense_key_table[] = -{ - { SSD_KEY_NO_SENSE, SS_NOP, "NO SENSE" }, - { SSD_KEY_RECOVERED_ERROR, SS_NOP|SSQ_PRINT_SENSE, "RECOVERED ERROR" }, - { - SSD_KEY_NOT_READY, SS_TUR|SSQ_MANY|SSQ_DECREMENT_COUNT|EBUSY, - "NOT READY" - }, - { SSD_KEY_MEDIUM_ERROR, SS_RDEF, "MEDIUM ERROR" }, - { SSD_KEY_HARDWARE_ERROR, SS_RDEF, "HARDWARE FAILURE" }, - { SSD_KEY_ILLEGAL_REQUEST, SS_FATAL|EINVAL, "ILLEGAL REQUEST" }, - { SSD_KEY_UNIT_ATTENTION, SS_FATAL|ENXIO, "UNIT ATTENTION" }, - { SSD_KEY_DATA_PROTECT, SS_FATAL|EACCES, "DATA PROTECT" }, - { SSD_KEY_BLANK_CHECK, SS_FATAL|ENOSPC, "BLANK CHECK" }, - { SSD_KEY_Vendor_Specific, SS_FATAL|EIO, "Vendor Specific" }, - { SSD_KEY_COPY_ABORTED, SS_FATAL|EIO, "COPY ABORTED" }, - { SSD_KEY_ABORTED_COMMAND, SS_RDEF, "ABORTED COMMAND" }, - { SSD_KEY_EQUAL, SS_NOP, "EQUAL" }, - { SSD_KEY_VOLUME_OVERFLOW, SS_FATAL|EIO, "VOLUME OVERFLOW" }, - { SSD_KEY_MISCOMPARE, SS_NOP, "MISCOMPARE" }, - { SSD_KEY_RESERVED, SS_FATAL|EIO, "RESERVED" } -}; - -static const int sense_key_table_size = - sizeof(sense_key_table)/sizeof(sense_key_table[0]); - -static struct asc_table_entry quantum_fireball_entries[] = { - {SST(0x04, 0x0b, SS_START|SSQ_DECREMENT_COUNT|ENXIO, - "Logical unit not ready, initializing cmd. required")} -}; - -static struct asc_table_entry sony_mo_entries[] = { - {SST(0x04, 0x00, SS_START|SSQ_DECREMENT_COUNT|ENXIO, - "Logical unit not ready, cause not reportable")} -}; - -static struct scsi_sense_quirk_entry sense_quirk_table[] = { - { - /* - * The Quantum Fireball ST and SE like to return 0x04 0x0b when - * they really should return 0x04 0x02. 0x04,0x0b isn't - * defined in any SCSI spec, and it isn't mentioned in the - * hardware manual for these drives. - */ - {T_DIRECT, SIP_MEDIA_FIXED, "QUANTUM", "FIREBALL S*", "*"}, - /*num_sense_keys*/0, - sizeof(quantum_fireball_entries)/sizeof(struct asc_table_entry), - /*sense key entries*/NULL, - quantum_fireball_entries - }, - { - /* - * This Sony MO drive likes to return 0x04, 0x00 when it - * isn't spun up. - */ - {T_DIRECT, SIP_MEDIA_REMOVABLE, "SONY", "SMO-*", "*"}, - /*num_sense_keys*/0, - sizeof(sony_mo_entries)/sizeof(struct asc_table_entry), - /*sense key entries*/NULL, - sony_mo_entries - } -}; - -static const int sense_quirk_table_size = - sizeof(sense_quirk_table)/sizeof(sense_quirk_table[0]); - -static struct asc_table_entry asc_table[] = { -/* - * From File: ASC-NUM.TXT - * SCSI ASC/ASCQ Assignments - * Numeric Sorted Listing - * as of 5/12/97 - * - * D - DIRECT ACCESS DEVICE (SBC) device column key - * .T - SEQUENTIAL ACCESS DEVICE (SSC) ------------------- - * . L - PRINTER DEVICE (SSC) blank = reserved - * . P - PROCESSOR DEVICE (SPC) not blank = allowed - * . .W - WRITE ONCE READ MULTIPLE DEVICE (SBC) - * . . R - CD DEVICE (MMC) - * . . S - SCANNER DEVICE (SGC) - * . . .O - OPTICAL MEMORY DEVICE (SBC) - * . . . M - MEDIA CHANGER DEVICE (SMC) - * . . . C - COMMUNICATION DEVICE (SSC) - * . . . .A - STORAGE ARRAY DEVICE (SCC) - * . . . . E - ENCLOSURE SERVICES DEVICE (SES) - * DTLPWRSOMCAE ASC ASCQ Action Description - * ------------ ---- ---- ------ -----------------------------------*/ -/* DTLPWRSOMCAE */{SST(0x00, 0x00, SS_NOP, - "No additional sense information") }, -/* T S */{SST(0x00, 0x01, SS_RDEF, - "Filemark detected") }, -/* T S */{SST(0x00, 0x02, SS_RDEF, - "End-of-partition/medium detected") }, -/* T */{SST(0x00, 0x03, SS_RDEF, - "Setmark detected") }, -/* T S */{SST(0x00, 0x04, SS_RDEF, - "Beginning-of-partition/medium detected") }, -/* T S */{SST(0x00, 0x05, SS_RDEF, - "End-of-data detected") }, -/* DTLPWRSOMCAE */{SST(0x00, 0x06, SS_RDEF, - "I/O process terminated") }, -/* R */{SST(0x00, 0x11, SS_FATAL|EBUSY, - "Audio play operation in progress") }, -/* R */{SST(0x00, 0x12, SS_NOP, - "Audio play operation paused") }, -/* R */{SST(0x00, 0x13, SS_NOP, - "Audio play operation successfully completed") }, -/* R */{SST(0x00, 0x14, SS_RDEF, - "Audio play operation stopped due to error") }, -/* R */{SST(0x00, 0x15, SS_NOP, - "No current audio status to return") }, -/* DTLPWRSOMCAE */{SST(0x00, 0x16, SS_FATAL|EBUSY, - "Operation in progress") }, -/* DTL WRSOM AE */{SST(0x00, 0x17, SS_RDEF, - "Cleaning requested") }, -/* D W O */{SST(0x01, 0x00, SS_RDEF, - "No index/sector signal") }, -/* D WR OM */{SST(0x02, 0x00, SS_RDEF, - "No seek complete") }, -/* DTL W SO */{SST(0x03, 0x00, SS_RDEF, - "Peripheral device write fault") }, -/* T */{SST(0x03, 0x01, SS_RDEF, - "No write current") }, -/* T */{SST(0x03, 0x02, SS_RDEF, - "Excessive write errors") }, -/* DTLPWRSOMCAE */{SST(0x04, 0x00, - SS_TUR|SSQ_DELAY|SSQ_MANY|SSQ_DECREMENT_COUNT|EIO, - "Logical unit not ready, cause not reportable") }, -/* DTLPWRSOMCAE */{SST(0x04, 0x01, - SS_TUR|SSQ_DELAY|SSQ_MANY|SSQ_DECREMENT_COUNT|EBUSY, - "Logical unit is in process of becoming ready") }, -/* DTLPWRSOMCAE */{SST(0x04, 0x02, SS_START|SSQ_DECREMENT_COUNT|ENXIO, - "Logical unit not ready, initializing cmd. required") }, -/* DTLPWRSOMCAE */{SST(0x04, 0x03, SS_FATAL|ENXIO, - "Logical unit not ready, manual intervention required")}, -/* DTL O */{SST(0x04, 0x04, SS_FATAL|EBUSY, - "Logical unit not ready, format in progress") }, -/* DT W OMCA */{SST(0x04, 0x05, SS_FATAL|EBUSY, - "Logical unit not ready, rebuild in progress") }, -/* DT W OMCA */{SST(0x04, 0x06, SS_FATAL|EBUSY, - "Logical unit not ready, recalculation in progress") }, -/* DTLPWRSOMCAE */{SST(0x04, 0x07, SS_FATAL|EBUSY, - "Logical unit not ready, operation in progress") }, -/* R */{SST(0x04, 0x08, SS_FATAL|EBUSY, - "Logical unit not ready, long write in progress") }, -/* DTL WRSOMCAE */{SST(0x05, 0x00, SS_RDEF, - "Logical unit does not respond to selection") }, -/* D WR OM */{SST(0x06, 0x00, SS_RDEF, - "No reference position found") }, -/* DTL WRSOM */{SST(0x07, 0x00, SS_RDEF, - "Multiple peripheral devices selected") }, -/* DTL WRSOMCAE */{SST(0x08, 0x00, SS_RDEF, - "Logical unit communication failure") }, -/* DTL WRSOMCAE */{SST(0x08, 0x01, SS_RDEF, - "Logical unit communication time-out") }, -/* DTL WRSOMCAE */{SST(0x08, 0x02, SS_RDEF, - "Logical unit communication parity error") }, -/* DT R OM */{SST(0x08, 0x03, SS_RDEF, - "Logical unit communication crc error (ultra-dma/32)")}, -/* DT WR O */{SST(0x09, 0x00, SS_RDEF, - "Track following error") }, -/* WR O */{SST(0x09, 0x01, SS_RDEF, - "Tracking servo failure") }, -/* WR O */{SST(0x09, 0x02, SS_RDEF, - "Focus servo failure") }, -/* WR O */{SST(0x09, 0x03, SS_RDEF, - "Spindle servo failure") }, -/* DT WR O */{SST(0x09, 0x04, SS_RDEF, - "Head select fault") }, -/* DTLPWRSOMCAE */{SST(0x0A, 0x00, SS_FATAL|ENOSPC, - "Error log overflow") }, -/* DTLPWRSOMCAE */{SST(0x0B, 0x00, SS_RDEF, - "Warning") }, -/* DTLPWRSOMCAE */{SST(0x0B, 0x01, SS_RDEF, - "Specified temperature exceeded") }, -/* DTLPWRSOMCAE */{SST(0x0B, 0x02, SS_RDEF, - "Enclosure degraded") }, -/* T RS */{SST(0x0C, 0x00, SS_RDEF, - "Write error") }, -/* D W O */{SST(0x0C, 0x01, SS_NOP|SSQ_PRINT_SENSE, - "Write error - recovered with auto reallocation") }, -/* D W O */{SST(0x0C, 0x02, SS_RDEF, - "Write error - auto reallocation failed") }, -/* D W O */{SST(0x0C, 0x03, SS_RDEF, - "Write error - recommend reassignment") }, -/* DT W O */{SST(0x0C, 0x04, SS_RDEF, - "Compression check miscompare error") }, -/* DT W O */{SST(0x0C, 0x05, SS_RDEF, - "Data expansion occurred during compression") }, -/* DT W O */{SST(0x0C, 0x06, SS_RDEF, - "Block not compressible") }, -/* R */{SST(0x0C, 0x07, SS_RDEF, - "Write error - recovery needed") }, -/* R */{SST(0x0C, 0x08, SS_RDEF, - "Write error - recovery failed") }, -/* R */{SST(0x0C, 0x09, SS_RDEF, - "Write error - loss of streaming") }, -/* R */{SST(0x0C, 0x0A, SS_RDEF, - "Write error - padding blocks added") }, -/* D W O */{SST(0x10, 0x00, SS_RDEF, - "ID CRC or ECC error") }, -/* DT WRSO */{SST(0x11, 0x00, SS_RDEF, - "Unrecovered read error") }, -/* DT W SO */{SST(0x11, 0x01, SS_RDEF, - "Read retries exhausted") }, -/* DT W SO */{SST(0x11, 0x02, SS_RDEF, - "Error too long to correct") }, -/* DT W SO */{SST(0x11, 0x03, SS_RDEF, - "Multiple read errors") }, -/* D W O */{SST(0x11, 0x04, SS_RDEF, - "Unrecovered read error - auto reallocate failed") }, -/* WR O */{SST(0x11, 0x05, SS_RDEF, - "L-EC uncorrectable error") }, -/* WR O */{SST(0x11, 0x06, SS_RDEF, - "CIRC unrecovered error") }, -/* W O */{SST(0x11, 0x07, SS_RDEF, - "Data re-synchronization error") }, -/* T */{SST(0x11, 0x08, SS_RDEF, - "Incomplete block read") }, -/* T */{SST(0x11, 0x09, SS_RDEF, - "No gap found") }, -/* DT O */{SST(0x11, 0x0A, SS_RDEF, - "Miscorrected error") }, -/* D W O */{SST(0x11, 0x0B, SS_RDEF, - "Unrecovered read error - recommend reassignment") }, -/* D W O */{SST(0x11, 0x0C, SS_RDEF, - "Unrecovered read error - recommend rewrite the data")}, -/* DT WR O */{SST(0x11, 0x0D, SS_RDEF, - "De-compression CRC error") }, -/* DT WR O */{SST(0x11, 0x0E, SS_RDEF, - "Cannot decompress using declared algorithm") }, -/* R */{SST(0x11, 0x0F, SS_RDEF, - "Error reading UPC/EAN number") }, -/* R */{SST(0x11, 0x10, SS_RDEF, - "Error reading ISRC number") }, -/* R */{SST(0x11, 0x11, SS_RDEF, - "Read error - loss of streaming") }, -/* D W O */{SST(0x12, 0x00, SS_RDEF, - "Address mark not found for id field") }, -/* D W O */{SST(0x13, 0x00, SS_RDEF, - "Address mark not found for data field") }, -/* DTL WRSO */{SST(0x14, 0x00, SS_RDEF, - "Recorded entity not found") }, -/* DT WR O */{SST(0x14, 0x01, SS_RDEF, - "Record not found") }, -/* T */{SST(0x14, 0x02, SS_RDEF, - "Filemark or setmark not found") }, -/* T */{SST(0x14, 0x03, SS_RDEF, - "End-of-data not found") }, -/* T */{SST(0x14, 0x04, SS_RDEF, - "Block sequence error") }, -/* DT W O */{SST(0x14, 0x05, SS_RDEF, - "Record not found - recommend reassignment") }, -/* DT W O */{SST(0x14, 0x06, SS_RDEF, - "Record not found - data auto-reallocated") }, -/* DTL WRSOM */{SST(0x15, 0x00, SS_RDEF, - "Random positioning error") }, -/* DTL WRSOM */{SST(0x15, 0x01, SS_RDEF, - "Mechanical positioning error") }, -/* DT WR O */{SST(0x15, 0x02, SS_RDEF, - "Positioning error detected by read of medium") }, -/* D W O */{SST(0x16, 0x00, SS_RDEF, - "Data synchronization mark error") }, -/* D W O */{SST(0x16, 0x01, SS_RDEF, - "Data sync error - data rewritten") }, -/* D W O */{SST(0x16, 0x02, SS_RDEF, - "Data sync error - recommend rewrite") }, -/* D W O */{SST(0x16, 0x03, SS_NOP|SSQ_PRINT_SENSE, - "Data sync error - data auto-reallocated") }, -/* D W O */{SST(0x16, 0x04, SS_RDEF, - "Data sync error - recommend reassignment") }, -/* DT WRSO */{SST(0x17, 0x00, SS_NOP|SSQ_PRINT_SENSE, - "Recovered data with no error correction applied") }, -/* DT WRSO */{SST(0x17, 0x01, SS_NOP|SSQ_PRINT_SENSE, - "Recovered data with retries") }, -/* DT WR O */{SST(0x17, 0x02, SS_NOP|SSQ_PRINT_SENSE, - "Recovered data with positive head offset") }, -/* DT WR O */{SST(0x17, 0x03, SS_NOP|SSQ_PRINT_SENSE, - "Recovered data with negative head offset") }, -/* WR O */{SST(0x17, 0x04, SS_NOP|SSQ_PRINT_SENSE, - "Recovered data with retries and/or CIRC applied") }, -/* D WR O */{SST(0x17, 0x05, SS_NOP|SSQ_PRINT_SENSE, - "Recovered data using previous sector id") }, -/* D W O */{SST(0x17, 0x06, SS_NOP|SSQ_PRINT_SENSE, - "Recovered data without ECC - data auto-reallocated") }, -/* D W O */{SST(0x17, 0x07, SS_NOP|SSQ_PRINT_SENSE, - "Recovered data without ECC - recommend reassignment")}, -/* D W O */{SST(0x17, 0x08, SS_NOP|SSQ_PRINT_SENSE, - "Recovered data without ECC - recommend rewrite") }, -/* D W O */{SST(0x17, 0x09, SS_NOP|SSQ_PRINT_SENSE, - "Recovered data without ECC - data rewritten") }, -/* D W O */{SST(0x18, 0x00, SS_NOP|SSQ_PRINT_SENSE, - "Recovered data with error correction applied") }, -/* D WR O */{SST(0x18, 0x01, SS_NOP|SSQ_PRINT_SENSE, - "Recovered data with error corr. & retries applied") }, -/* D WR O */{SST(0x18, 0x02, SS_NOP|SSQ_PRINT_SENSE, - "Recovered data - data auto-reallocated") }, -/* R */{SST(0x18, 0x03, SS_NOP|SSQ_PRINT_SENSE, - "Recovered data with CIRC") }, -/* R */{SST(0x18, 0x04, SS_NOP|SSQ_PRINT_SENSE, - "Recovered data with L-EC") }, -/* D WR O */{SST(0x18, 0x05, SS_NOP|SSQ_PRINT_SENSE, - "Recovered data - recommend reassignment") }, -/* D WR O */{SST(0x18, 0x06, SS_NOP|SSQ_PRINT_SENSE, - "Recovered data - recommend rewrite") }, -/* D W O */{SST(0x18, 0x07, SS_NOP|SSQ_PRINT_SENSE, - "Recovered data with ECC - data rewritten") }, -/* D O */{SST(0x19, 0x00, SS_RDEF, - "Defect list error") }, -/* D O */{SST(0x19, 0x01, SS_RDEF, - "Defect list not available") }, -/* D O */{SST(0x19, 0x02, SS_RDEF, - "Defect list error in primary list") }, -/* D O */{SST(0x19, 0x03, SS_RDEF, - "Defect list error in grown list") }, -/* DTLPWRSOMCAE */{SST(0x1A, 0x00, SS_RDEF, - "Parameter list length error") }, -/* DTLPWRSOMCAE */{SST(0x1B, 0x00, SS_RDEF, - "Synchronous data transfer error") }, -/* D O */{SST(0x1C, 0x00, SS_RDEF, - "Defect list not found") }, -/* D O */{SST(0x1C, 0x01, SS_RDEF, - "Primary defect list not found") }, -/* D O */{SST(0x1C, 0x02, SS_RDEF, - "Grown defect list not found") }, -/* D W O */{SST(0x1D, 0x00, SS_FATAL, - "Miscompare during verify operation" )}, -/* D W O */{SST(0x1E, 0x00, SS_NOP|SSQ_PRINT_SENSE, - "Recovered id with ecc correction") }, -/* D O */{SST(0x1F, 0x00, SS_RDEF, - "Partial defect list transfer") }, -/* DTLPWRSOMCAE */{SST(0x20, 0x00, SS_FATAL|EINVAL, - "Invalid command operation code") }, -/* DT WR OM */{SST(0x21, 0x00, SS_FATAL|EINVAL, - "Logical block address out of range" )}, -/* DT WR OM */{SST(0x21, 0x01, SS_FATAL|EINVAL, - "Invalid element address") }, -/* D */{SST(0x22, 0x00, SS_FATAL|EINVAL, - "Illegal function") }, /* Deprecated. Use 20 00, 24 00, or 26 00 instead */ -/* DTLPWRSOMCAE */{SST(0x24, 0x00, SS_FATAL|EINVAL, - "Invalid field in CDB") }, -/* DTLPWRSOMCAE */{SST(0x25, 0x00, SS_FATAL|ENXIO, - "Logical unit not supported") }, -/* DTLPWRSOMCAE */{SST(0x26, 0x00, SS_FATAL|EINVAL, - "Invalid field in parameter list") }, -/* DTLPWRSOMCAE */{SST(0x26, 0x01, SS_FATAL|EINVAL, - "Parameter not supported") }, -/* DTLPWRSOMCAE */{SST(0x26, 0x02, SS_FATAL|EINVAL, - "Parameter value invalid") }, -/* DTLPWRSOMCAE */{SST(0x26, 0x03, SS_FATAL|EINVAL, - "Threshold parameters not supported") }, -/* DTLPWRSOMCAE */{SST(0x26, 0x04, SS_FATAL|EINVAL, - "Invalid release of active persistent reservation") }, -/* DT W O */{SST(0x27, 0x00, SS_FATAL|EACCES, - "Write protected") }, -/* DT W O */{SST(0x27, 0x01, SS_FATAL|EACCES, - "Hardware write protected") }, -/* DT W O */{SST(0x27, 0x02, SS_FATAL|EACCES, - "Logical unit software write protected") }, -/* T */{SST(0x27, 0x03, SS_FATAL|EACCES, - "Associated write protect") }, -/* T */{SST(0x27, 0x04, SS_FATAL|EACCES, - "Persistent write protect") }, -/* T */{SST(0x27, 0x05, SS_FATAL|EACCES, - "Permanent write protect") }, -/* DTLPWRSOMCAE */{SST(0x28, 0x00, SS_RDEF, - "Not ready to ready change, medium may have changed") }, -/* DTLPWRSOMCAE */{SST(0x28, 0x01, SS_FATAL|ENXIO, - "Import or export element accessed") }, -/* - * XXX JGibbs - All of these should use the same errno, but I don't think - * ENXIO is the correct choice. Should we borrow from the networking - * errnos? ECONNRESET anyone? - */ -/* DTLPWRSOMCAE */{SST(0x29, 0x00, SS_RDEF, - "Power on, reset, or bus device reset occurred") }, -/* DTLPWRSOMCAE */{SST(0x29, 0x01, SS_RDEF, - "Power on occurred") }, -/* DTLPWRSOMCAE */{SST(0x29, 0x02, SS_RDEF, - "Scsi bus reset occurred") }, -/* DTLPWRSOMCAE */{SST(0x29, 0x03, SS_RDEF, - "Bus device reset function occurred") }, -/* DTLPWRSOMCAE */{SST(0x29, 0x04, SS_RDEF, - "Device internal reset") }, -/* DTLPWRSOMCAE */{SST(0x29, 0x05, SS_RDEF, - "Transceiver mode changed to single-ended") }, -/* DTLPWRSOMCAE */{SST(0x29, 0x06, SS_RDEF, - "Transceiver mode changed to LVD") }, -/* DTL WRSOMCAE */{SST(0x2A, 0x00, SS_RDEF, - "Parameters changed") }, -/* DTL WRSOMCAE */{SST(0x2A, 0x01, SS_RDEF, - "Mode parameters changed") }, -/* DTL WRSOMCAE */{SST(0x2A, 0x02, SS_RDEF, - "Log parameters changed") }, -/* DTLPWRSOMCAE */{SST(0x2A, 0x03, SS_RDEF, - "Reservations preempted") }, -/* DTLPWRSO C */{SST(0x2B, 0x00, SS_RDEF, - "Copy cannot execute since host cannot disconnect") }, -/* DTLPWRSOMCAE */{SST(0x2C, 0x00, SS_RDEF, - "Command sequence error") }, -/* S */{SST(0x2C, 0x01, SS_RDEF, - "Too many windows specified") }, -/* S */{SST(0x2C, 0x02, SS_RDEF, - "Invalid combination of windows specified") }, -/* R */{SST(0x2C, 0x03, SS_RDEF, - "Current program area is not empty") }, -/* R */{SST(0x2C, 0x04, SS_RDEF, - "Current program area is empty") }, -/* T */{SST(0x2D, 0x00, SS_RDEF, - "Overwrite error on update in place") }, -/* DTLPWRSOMCAE */{SST(0x2F, 0x00, SS_RDEF, - "Commands cleared by another initiator") }, -/* DT WR OM */{SST(0x30, 0x00, SS_RDEF, - "Incompatible medium installed") }, -/* DT WR O */{SST(0x30, 0x01, SS_RDEF, - "Cannot read medium - unknown format") }, -/* DT WR O */{SST(0x30, 0x02, SS_RDEF, - "Cannot read medium - incompatible format") }, -/* DT */{SST(0x30, 0x03, SS_RDEF, - "Cleaning cartridge installed") }, -/* DT WR O */{SST(0x30, 0x04, SS_RDEF, - "Cannot write medium - unknown format") }, -/* DT WR O */{SST(0x30, 0x05, SS_RDEF, - "Cannot write medium - incompatible format") }, -/* DT W O */{SST(0x30, 0x06, SS_RDEF, - "Cannot format medium - incompatible medium") }, -/* DTL WRSOM AE */{SST(0x30, 0x07, SS_RDEF, - "Cleaning failure") }, -/* R */{SST(0x30, 0x08, SS_RDEF, - "Cannot write - application code mismatch") }, -/* R */{SST(0x30, 0x09, SS_RDEF, - "Current session not fixated for append") }, -/* DT WR O */{SST(0x31, 0x00, SS_RDEF, - "Medium format corrupted") }, -/* D L R O */{SST(0x31, 0x01, SS_RDEF, - "Format command failed") }, -/* D W O */{SST(0x32, 0x00, SS_RDEF, - "No defect spare location available") }, -/* D W O */{SST(0x32, 0x01, SS_RDEF, - "Defect list update failure") }, -/* T */{SST(0x33, 0x00, SS_RDEF, - "Tape length error") }, -/* DTLPWRSOMCAE */{SST(0x34, 0x00, SS_RDEF, - "Enclosure failure") }, -/* DTLPWRSOMCAE */{SST(0x35, 0x00, SS_RDEF, - "Enclosure services failure") }, -/* DTLPWRSOMCAE */{SST(0x35, 0x01, SS_RDEF, - "Unsupported enclosure function") }, -/* DTLPWRSOMCAE */{SST(0x35, 0x02, SS_RDEF, - "Enclosure services unavailable") }, -/* DTLPWRSOMCAE */{SST(0x35, 0x03, SS_RDEF, - "Enclosure services transfer failure") }, -/* DTLPWRSOMCAE */{SST(0x35, 0x04, SS_RDEF, - "Enclosure services transfer refused") }, -/* L */{SST(0x36, 0x00, SS_RDEF, - "Ribbon, ink, or toner failure") }, -/* DTL WRSOMCAE */{SST(0x37, 0x00, SS_RDEF, - "Rounded parameter") }, -/* DTL WRSOMCAE */{SST(0x39, 0x00, SS_RDEF, - "Saving parameters not supported") }, -/* DTL WRSOM */{SST(0x3A, 0x00, SS_NOP, - "Medium not present") }, -/* DT WR OM */{SST(0x3A, 0x01, SS_NOP, - "Medium not present - tray closed") }, -/* DT WR OM */{SST(0x3A, 0x01, SS_NOP, - "Medium not present - tray open") }, -/* DT WR OM */{SST(0x3A, 0x03, SS_NOP, - "Medium not present - Loadable") }, -/* DT WR OM */{SST(0x3A, 0x04, SS_NOP, - "Medium not present - medium auxiliary " - "memory accessible") }, -/* DT WR OM */{SST(0x3A, 0xFF, SS_NOP, NULL) },/* Range 0x05->0xFF */ -/* TL */{SST(0x3B, 0x00, SS_RDEF, - "Sequential positioning error") }, -/* T */{SST(0x3B, 0x01, SS_RDEF, - "Tape position error at beginning-of-medium") }, -/* T */{SST(0x3B, 0x02, SS_RDEF, - "Tape position error at end-of-medium") }, -/* L */{SST(0x3B, 0x03, SS_RDEF, - "Tape or electronic vertical forms unit not ready") }, -/* L */{SST(0x3B, 0x04, SS_RDEF, - "Slew failure") }, -/* L */{SST(0x3B, 0x05, SS_RDEF, - "Paper jam") }, -/* L */{SST(0x3B, 0x06, SS_RDEF, - "Failed to sense top-of-form") }, -/* L */{SST(0x3B, 0x07, SS_RDEF, - "Failed to sense bottom-of-form") }, -/* T */{SST(0x3B, 0x08, SS_RDEF, - "Reposition error") }, -/* S */{SST(0x3B, 0x09, SS_RDEF, - "Read past end of medium") }, -/* S */{SST(0x3B, 0x0A, SS_RDEF, - "Read past beginning of medium") }, -/* S */{SST(0x3B, 0x0B, SS_RDEF, - "Position past end of medium") }, -/* T S */{SST(0x3B, 0x0C, SS_RDEF, - "Position past beginning of medium") }, -/* DT WR OM */{SST(0x3B, 0x0D, SS_FATAL|ENOSPC, - "Medium destination element full") }, -/* DT WR OM */{SST(0x3B, 0x0E, SS_RDEF, - "Medium source element empty") }, -/* R */{SST(0x3B, 0x0F, SS_RDEF, - "End of medium reached") }, -/* DT WR OM */{SST(0x3B, 0x11, SS_RDEF, - "Medium magazine not accessible") }, -/* DT WR OM */{SST(0x3B, 0x12, SS_RDEF, - "Medium magazine removed") }, -/* DT WR OM */{SST(0x3B, 0x13, SS_RDEF, - "Medium magazine inserted") }, -/* DT WR OM */{SST(0x3B, 0x14, SS_RDEF, - "Medium magazine locked") }, -/* DT WR OM */{SST(0x3B, 0x15, SS_RDEF, - "Medium magazine unlocked") }, -/* DTLPWRSOMCAE */{SST(0x3D, 0x00, SS_RDEF, - "Invalid bits in identify message") }, -/* DTLPWRSOMCAE */{SST(0x3E, 0x00, SS_RDEF, - "Logical unit has not self-configured yet") }, -/* DTLPWRSOMCAE */{SST(0x3E, 0x01, SS_RDEF, - "Logical unit failure") }, -/* DTLPWRSOMCAE */{SST(0x3E, 0x02, SS_RDEF, - "Timeout on logical unit") }, -/* DTLPWRSOMCAE */{SST(0x3F, 0x00, SS_RDEF, - "Target operating conditions have changed") }, -/* DTLPWRSOMCAE */{SST(0x3F, 0x01, SS_RDEF, - "Microcode has been changed") }, -/* DTLPWRSOMC */{SST(0x3F, 0x02, SS_RDEF, - "Changed operating definition") }, -/* DTLPWRSOMCAE */{SST(0x3F, 0x03, SS_INQ_REFRESH|SSQ_DECREMENT_COUNT, - "Inquiry data has changed") }, -/* DT WR OMCAE */{SST(0x3F, 0x04, SS_RDEF, - "Component device attached") }, -/* DT WR OMCAE */{SST(0x3F, 0x05, SS_RDEF, - "Device identifier changed") }, -/* DT WR OMCAE */{SST(0x3F, 0x06, SS_RDEF, - "Redundancy group created or modified") }, -/* DT WR OMCAE */{SST(0x3F, 0x07, SS_RDEF, - "Redundancy group deleted") }, -/* DT WR OMCAE */{SST(0x3F, 0x08, SS_RDEF, - "Spare created or modified") }, -/* DT WR OMCAE */{SST(0x3F, 0x09, SS_RDEF, - "Spare deleted") }, -/* DT WR OMCAE */{SST(0x3F, 0x0A, SS_RDEF, - "Volume set created or modified") }, -/* DT WR OMCAE */{SST(0x3F, 0x0B, SS_RDEF, - "Volume set deleted") }, -/* DT WR OMCAE */{SST(0x3F, 0x0C, SS_RDEF, - "Volume set deassigned") }, -/* DT WR OMCAE */{SST(0x3F, 0x0D, SS_RDEF, - "Volume set reassigned") }, -/* DTLPWRSOMCAE */{SST(0x3F, 0x0E, SS_RDEF, - "Reported luns data has changed") }, -/* DTLPWRSOMCAE */{SST(0x3F, 0x0F, SS_RETRY|SSQ_DECREMENT_COUNT - | SSQ_DELAY_RANDOM|EBUSY, - "Echo buffer overwritten") }, -/* DT WR OM B*/{SST(0x3F, 0x0F, SS_RDEF, "Medium Loadable") }, -/* DT WR OM B*/{SST(0x3F, 0x0F, SS_RDEF, - "Medium auxiliary memory accessible") }, -/* D */{SST(0x40, 0x00, SS_RDEF, - "Ram failure") }, /* deprecated - use 40 NN instead */ -/* DTLPWRSOMCAE */{SST(0x40, 0x80, SS_RDEF, - "Diagnostic failure: ASCQ = Component ID") }, -/* DTLPWRSOMCAE */{SST(0x40, 0xFF, SS_RDEF|SSQ_RANGE, - NULL) },/* Range 0x80->0xFF */ -/* D */{SST(0x41, 0x00, SS_RDEF, - "Data path failure") }, /* deprecated - use 40 NN instead */ -/* D */{SST(0x42, 0x00, SS_RDEF, - "Power-on or self-test failure") }, /* deprecated - use 40 NN instead */ -/* DTLPWRSOMCAE */{SST(0x43, 0x00, SS_RDEF, - "Message error") }, -/* DTLPWRSOMCAE */{SST(0x44, 0x00, SS_RDEF, - "Internal target failure") }, -/* DTLPWRSOMCAE */{SST(0x45, 0x00, SS_RDEF, - "Select or reselect failure") }, -/* DTLPWRSOMC */{SST(0x46, 0x00, SS_RDEF, - "Unsuccessful soft reset") }, -/* DTLPWRSOMCAE */{SST(0x47, 0x00, SS_RDEF|SSQ_FALLBACK, - "SCSI parity error") }, -/* DTLPWRSOMCAE */{SST(0x47, 0x01, SS_RDEF|SSQ_FALLBACK, - "Data Phase CRC error detected") }, -/* DTLPWRSOMCAE */{SST(0x47, 0x02, SS_RDEF|SSQ_FALLBACK, - "SCSI parity error detected during ST data phase") }, -/* DTLPWRSOMCAE */{SST(0x47, 0x03, SS_RDEF|SSQ_FALLBACK, - "Information Unit iuCRC error") }, -/* DTLPWRSOMCAE */{SST(0x47, 0x04, SS_RDEF|SSQ_FALLBACK, - "Asynchronous information protection error detected") }, -/* DTLPWRSOMCAE */{SST(0x47, 0x05, SS_RDEF|SSQ_FALLBACK, - "Protocol server CRC error") }, -/* DTLPWRSOMCAE */{SST(0x48, 0x00, SS_RDEF|SSQ_FALLBACK, - "Initiator detected error message received") }, -/* DTLPWRSOMCAE */{SST(0x49, 0x00, SS_RDEF, - "Invalid message error") }, -/* DTLPWRSOMCAE */{SST(0x4A, 0x00, SS_RDEF, - "Command phase error") }, -/* DTLPWRSOMCAE */{SST(0x4B, 0x00, SS_RDEF, - "Data phase error") }, -/* DTLPWRSOMCAE */{SST(0x4C, 0x00, SS_RDEF, - "Logical unit failed self-configuration") }, -/* DTLPWRSOMCAE */{SST(0x4D, 0x00, SS_RDEF, - "Tagged overlapped commands: ASCQ = Queue tag ID") }, -/* DTLPWRSOMCAE */{SST(0x4D, 0xFF, SS_RDEF|SSQ_RANGE, - NULL)}, /* Range 0x00->0xFF */ -/* DTLPWRSOMCAE */{SST(0x4E, 0x00, SS_RDEF, - "Overlapped commands attempted") }, -/* T */{SST(0x50, 0x00, SS_RDEF, - "Write append error") }, -/* T */{SST(0x50, 0x01, SS_RDEF, - "Write append position error") }, -/* T */{SST(0x50, 0x02, SS_RDEF, - "Position error related to timing") }, -/* T O */{SST(0x51, 0x00, SS_RDEF, - "Erase failure") }, -/* T */{SST(0x52, 0x00, SS_RDEF, - "Cartridge fault") }, -/* DTL WRSOM */{SST(0x53, 0x00, SS_RDEF, - "Media load or eject failed") }, -/* T */{SST(0x53, 0x01, SS_RDEF, - "Unload tape failure") }, -/* DT WR OM */{SST(0x53, 0x02, SS_RDEF, - "Medium removal prevented") }, -/* P */{SST(0x54, 0x00, SS_RDEF, - "Scsi to host system interface failure") }, -/* P */{SST(0x55, 0x00, SS_RDEF, - "System resource failure") }, -/* D O */{SST(0x55, 0x01, SS_FATAL|ENOSPC, - "System buffer full") }, -/* R */{SST(0x57, 0x00, SS_RDEF, - "Unable to recover table-of-contents") }, -/* O */{SST(0x58, 0x00, SS_RDEF, - "Generation does not exist") }, -/* O */{SST(0x59, 0x00, SS_RDEF, - "Updated block read") }, -/* DTLPWRSOM */{SST(0x5A, 0x00, SS_RDEF, - "Operator request or state change input") }, -/* DT WR OM */{SST(0x5A, 0x01, SS_RDEF, - "Operator medium removal request") }, -/* DT W O */{SST(0x5A, 0x02, SS_RDEF, - "Operator selected write protect") }, -/* DT W O */{SST(0x5A, 0x03, SS_RDEF, - "Operator selected write permit") }, -/* DTLPWRSOM */{SST(0x5B, 0x00, SS_RDEF, - "Log exception") }, -/* DTLPWRSOM */{SST(0x5B, 0x01, SS_RDEF, - "Threshold condition met") }, -/* DTLPWRSOM */{SST(0x5B, 0x02, SS_RDEF, - "Log counter at maximum") }, -/* DTLPWRSOM */{SST(0x5B, 0x03, SS_RDEF, - "Log list codes exhausted") }, -/* D O */{SST(0x5C, 0x00, SS_RDEF, - "RPL status change") }, -/* D O */{SST(0x5C, 0x01, SS_NOP|SSQ_PRINT_SENSE, - "Spindles synchronized") }, -/* D O */{SST(0x5C, 0x02, SS_RDEF, - "Spindles not synchronized") }, -/* DTLPWRSOMCAE */{SST(0x5D, 0x00, SS_RDEF, - "Failure prediction threshold exceeded") }, -/* DTLPWRSOMCAE */{SST(0x5D, 0xFF, SS_RDEF, - "Failure prediction threshold exceeded (false)") }, -/* DTLPWRSO CA */{SST(0x5E, 0x00, SS_RDEF, - "Low power condition on") }, -/* DTLPWRSO CA */{SST(0x5E, 0x01, SS_RDEF, - "Idle condition activated by timer") }, -/* DTLPWRSO CA */{SST(0x5E, 0x02, SS_RDEF, - "Standby condition activated by timer") }, -/* DTLPWRSO CA */{SST(0x5E, 0x03, SS_RDEF, - "Idle condition activated by command") }, -/* DTLPWRSO CA */{SST(0x5E, 0x04, SS_RDEF, - "Standby condition activated by command") }, -/* S */{SST(0x60, 0x00, SS_RDEF, - "Lamp failure") }, -/* S */{SST(0x61, 0x00, SS_RDEF, - "Video acquisition error") }, -/* S */{SST(0x61, 0x01, SS_RDEF, - "Unable to acquire video") }, -/* S */{SST(0x61, 0x02, SS_RDEF, - "Out of focus") }, -/* S */{SST(0x62, 0x00, SS_RDEF, - "Scan head positioning error") }, -/* R */{SST(0x63, 0x00, SS_RDEF, - "End of user area encountered on this track") }, -/* R */{SST(0x63, 0x01, SS_FATAL|ENOSPC, - "Packet does not fit in available space") }, -/* R */{SST(0x64, 0x00, SS_RDEF, - "Illegal mode for this track") }, -/* R */{SST(0x64, 0x01, SS_RDEF, - "Invalid packet size") }, -/* DTLPWRSOMCAE */{SST(0x65, 0x00, SS_RDEF, - "Voltage fault") }, -/* S */{SST(0x66, 0x00, SS_RDEF, - "Automatic document feeder cover up") }, -/* S */{SST(0x66, 0x01, SS_RDEF, - "Automatic document feeder lift up") }, -/* S */{SST(0x66, 0x02, SS_RDEF, - "Document jam in automatic document feeder") }, -/* S */{SST(0x66, 0x03, SS_RDEF, - "Document miss feed automatic in document feeder") }, -/* A */{SST(0x67, 0x00, SS_RDEF, - "Configuration failure") }, -/* A */{SST(0x67, 0x01, SS_RDEF, - "Configuration of incapable logical units failed") }, -/* A */{SST(0x67, 0x02, SS_RDEF, - "Add logical unit failed") }, -/* A */{SST(0x67, 0x03, SS_RDEF, - "Modification of logical unit failed") }, -/* A */{SST(0x67, 0x04, SS_RDEF, - "Exchange of logical unit failed") }, -/* A */{SST(0x67, 0x05, SS_RDEF, - "Remove of logical unit failed") }, -/* A */{SST(0x67, 0x06, SS_RDEF, - "Attachment of logical unit failed") }, -/* A */{SST(0x67, 0x07, SS_RDEF, - "Creation of logical unit failed") }, -/* A */{SST(0x68, 0x00, SS_RDEF, - "Logical unit not configured") }, -/* A */{SST(0x69, 0x00, SS_RDEF, - "Data loss on logical unit") }, -/* A */{SST(0x69, 0x01, SS_RDEF, - "Multiple logical unit failures") }, -/* A */{SST(0x69, 0x02, SS_RDEF, - "Parity/data mismatch") }, -/* A */{SST(0x6A, 0x00, SS_RDEF, - "Informational, refer to log") }, -/* A */{SST(0x6B, 0x00, SS_RDEF, - "State change has occurred") }, -/* A */{SST(0x6B, 0x01, SS_RDEF, - "Redundancy level got better") }, -/* A */{SST(0x6B, 0x02, SS_RDEF, - "Redundancy level got worse") }, -/* A */{SST(0x6C, 0x00, SS_RDEF, - "Rebuild failure occurred") }, -/* A */{SST(0x6D, 0x00, SS_RDEF, - "Recalculate failure occurred") }, -/* A */{SST(0x6E, 0x00, SS_RDEF, - "Command to logical unit failed") }, -/* T */{SST(0x70, 0x00, SS_RDEF, - "Decompression exception short: ASCQ = Algorithm ID") }, -/* T */{SST(0x70, 0xFF, SS_RDEF|SSQ_RANGE, - NULL) }, /* Range 0x00 -> 0xFF */ -/* T */{SST(0x71, 0x00, SS_RDEF, - "Decompression exception long: ASCQ = Algorithm ID") }, -/* T */{SST(0x71, 0xFF, SS_RDEF|SSQ_RANGE, - NULL) }, /* Range 0x00 -> 0xFF */ -/* R */{SST(0x72, 0x00, SS_RDEF, - "Session fixation error") }, -/* R */{SST(0x72, 0x01, SS_RDEF, - "Session fixation error writing lead-in") }, -/* R */{SST(0x72, 0x02, SS_RDEF, - "Session fixation error writing lead-out") }, -/* R */{SST(0x72, 0x03, SS_RDEF, - "Session fixation error - incomplete track in session") }, -/* R */{SST(0x72, 0x04, SS_RDEF, - "Empty or partially written reserved track") }, -/* R */{SST(0x73, 0x00, SS_RDEF, - "CD control error") }, -/* R */{SST(0x73, 0x01, SS_RDEF, - "Power calibration area almost full") }, -/* R */{SST(0x73, 0x02, SS_FATAL|ENOSPC, - "Power calibration area is full") }, -/* R */{SST(0x73, 0x03, SS_RDEF, - "Power calibration area error") }, -/* R */{SST(0x73, 0x04, SS_RDEF, - "Program memory area update failure") }, -/* R */{SST(0x73, 0x05, SS_RDEF, - "program memory area is full") } -}; - -static const int asc_table_size = sizeof(asc_table)/sizeof(asc_table[0]); - -struct asc_key -{ - int asc; - int ascq; -}; - -static int -ascentrycomp(const void *key, const void *member) -{ - int asc; - int ascq; - const struct asc_table_entry *table_entry; - - asc = ((const struct asc_key *)key)->asc; - ascq = ((const struct asc_key *)key)->ascq; - table_entry = (const struct asc_table_entry *)member; - - if (asc >= table_entry->asc) { - - if (asc > table_entry->asc) - return (1); - - if (ascq <= table_entry->ascq) { - /* Check for ranges */ - if (ascq == table_entry->ascq - || ((table_entry->action & SSQ_RANGE) != 0 - && ascq >= (table_entry - 1)->ascq)) - return (0); - return (-1); - } - return (1); - } - return (-1); -} - -static int -senseentrycomp(const void *key, const void *member) -{ - int sense_key; - const struct sense_key_table_entry *table_entry; - - sense_key = *((const int *)key); - table_entry = (const struct sense_key_table_entry *)member; - - if (sense_key >= table_entry->sense_key) { - if (sense_key == table_entry->sense_key) - return (0); - return (1); - } - return (-1); -} - -static void -fetchtableentries(int sense_key, int asc, int ascq, - struct scsi_inquiry_data *inq_data, - const struct sense_key_table_entry **sense_entry, - const struct asc_table_entry **asc_entry) -{ - void *match; - const struct asc_table_entry *asc_tables[2]; - const struct sense_key_table_entry *sense_tables[2]; - struct asc_key asc_ascq; - size_t asc_tables_size[2]; - size_t sense_tables_size[2]; - int num_asc_tables; - int num_sense_tables; - int i; - - /* Default to failure */ - *sense_entry = NULL; - *asc_entry = NULL; - match = NULL; - if (inq_data != NULL) - match = cam_quirkmatch((void *)inq_data, - (void *)sense_quirk_table, - sense_quirk_table_size, - sizeof(*sense_quirk_table), - aic_inquiry_match); - - if (match != NULL) { - struct scsi_sense_quirk_entry *quirk; - - quirk = (struct scsi_sense_quirk_entry *)match; - asc_tables[0] = quirk->asc_info; - asc_tables_size[0] = quirk->num_ascs; - asc_tables[1] = asc_table; - asc_tables_size[1] = asc_table_size; - num_asc_tables = 2; - sense_tables[0] = quirk->sense_key_info; - sense_tables_size[0] = quirk->num_sense_keys; - sense_tables[1] = sense_key_table; - sense_tables_size[1] = sense_key_table_size; - num_sense_tables = 2; - } else { - asc_tables[0] = asc_table; - asc_tables_size[0] = asc_table_size; - num_asc_tables = 1; - sense_tables[0] = sense_key_table; - sense_tables_size[0] = sense_key_table_size; - num_sense_tables = 1; - } - - asc_ascq.asc = asc; - asc_ascq.ascq = ascq; - for (i = 0; i < num_asc_tables; i++) { - void *found_entry; - - found_entry = scsibsearch(&asc_ascq, asc_tables[i], - asc_tables_size[i], - sizeof(**asc_tables), - ascentrycomp); - - if (found_entry) { - *asc_entry = (struct asc_table_entry *)found_entry; - break; - } - } - - for (i = 0; i < num_sense_tables; i++) { - void *found_entry; - - found_entry = scsibsearch(&sense_key, sense_tables[i], - sense_tables_size[i], - sizeof(**sense_tables), - senseentrycomp); - - if (found_entry) { - *sense_entry = - (struct sense_key_table_entry *)found_entry; - break; - } - } -} - -static void * -scsibsearch(const void *key, const void *base, size_t nmemb, size_t size, - int (*compar)(const void *, const void *)) -{ - const void *entry; - u_int l; - u_int u; - u_int m; - - l = -1; - u = nmemb; - while (l + 1 != u) { - m = (l + u) / 2; - entry = base + m * size; - if (compar(key, entry) > 0) - l = m; - else - u = m; - } - - entry = base + u * size; - if (u == nmemb - || compar(key, entry) != 0) - return (NULL); - - return ((void *)entry); -} - -/* - * Compare string with pattern, returning 0 on match. - * Short pattern matches trailing blanks in name, - * wildcard '*' in pattern matches rest of name, - * wildcard '?' matches a single non-space character. - */ -static int -cam_strmatch(const uint8_t *str, const uint8_t *pattern, int str_len) -{ - - while (*pattern != '\0'&& str_len > 0) { - - if (*pattern == '*') { - return (0); - } - if ((*pattern != *str) - && (*pattern != '?' || *str == ' ')) { - return (1); - } - pattern++; - str++; - str_len--; - } - while (str_len > 0 && *str++ == ' ') - str_len--; - - return (str_len); -} - -static caddr_t -cam_quirkmatch(caddr_t target, caddr_t quirk_table, int num_entries, - int entry_size, cam_quirkmatch_t *comp_func) -{ - for (; num_entries > 0; num_entries--, quirk_table += entry_size) { - if ((*comp_func)(target, quirk_table) == 0) - return (quirk_table); - } - return (NULL); -} - -void -aic_sense_desc(int sense_key, int asc, int ascq, - struct scsi_inquiry_data *inq_data, - const char **sense_key_desc, const char **asc_desc) -{ - const struct asc_table_entry *asc_entry; - const struct sense_key_table_entry *sense_entry; - - fetchtableentries(sense_key, asc, ascq, - inq_data, - &sense_entry, - &asc_entry); - - *sense_key_desc = sense_entry->desc; - - if (asc_entry != NULL) - *asc_desc = asc_entry->desc; - else if (asc >= 0x80 && asc <= 0xff) - *asc_desc = "Vendor Specific ASC"; - else if (ascq >= 0x80 && ascq <= 0xff) - *asc_desc = "Vendor Specific ASCQ"; - else - *asc_desc = "Reserved ASC/ASCQ pair"; -} - -/* - * Given sense and device type information, return the appropriate action. - * If we do not understand the specific error as identified by the ASC/ASCQ - * pair, fall back on the more generic actions derived from the sense key. - */ -aic_sense_action -aic_sense_error_action(struct scsi_sense_data *sense_data, - struct scsi_inquiry_data *inq_data, uint32_t sense_flags) -{ - const struct asc_table_entry *asc_entry; - const struct sense_key_table_entry *sense_entry; - int error_code, sense_key, asc, ascq; - aic_sense_action action; - - scsi_extract_sense(sense_data, &error_code, &sense_key, &asc, &ascq); - - if (error_code == SSD_DEFERRED_ERROR) { - /* - * XXX dufault@FreeBSD.org - * This error doesn't relate to the command associated - * with this request sense. A deferred error is an error - * for a command that has already returned GOOD status - * (see SCSI2 8.2.14.2). - * - * By my reading of that section, it looks like the current - * command has been cancelled, we should now clean things up - * (hopefully recovering any lost data) and then retry the - * current command. There are two easy choices, both wrong: - * - * 1. Drop through (like we had been doing), thus treating - * this as if the error were for the current command and - * return and stop the current command. - * - * 2. Issue a retry (like I made it do) thus hopefully - * recovering the current transfer, and ignoring the - * fact that we've dropped a command. - * - * These should probably be handled in a device specific - * sense handler or punted back up to a user mode daemon - */ - action = SS_RETRY|SSQ_DECREMENT_COUNT|SSQ_PRINT_SENSE; - } else { - fetchtableentries(sense_key, asc, ascq, - inq_data, - &sense_entry, - &asc_entry); - - /* - * Override the 'No additional Sense' entry (0,0) - * with the error action of the sense key. - */ - if (asc_entry != NULL - && (asc != 0 || ascq != 0)) - action = asc_entry->action; - else - action = sense_entry->action; - - if (sense_key == SSD_KEY_RECOVERED_ERROR) { - /* - * The action succeeded but the device wants - * the user to know that some recovery action - * was required. - */ - action &= ~(SS_MASK|SSQ_MASK|SS_ERRMASK); - action |= SS_NOP|SSQ_PRINT_SENSE; - } else if (sense_key == SSD_KEY_ILLEGAL_REQUEST) { - if ((sense_flags & SF_QUIET_IR) != 0) - action &= ~SSQ_PRINT_SENSE; - } else if (sense_key == SSD_KEY_UNIT_ATTENTION) { - if ((sense_flags & SF_RETRY_UA) != 0 - && (action & SS_MASK) == SS_FAIL) { - action &= ~(SS_MASK|SSQ_MASK); - action |= SS_RETRY|SSQ_DECREMENT_COUNT| - SSQ_PRINT_SENSE; - } - } - } - - if ((sense_flags & SF_PRINT_ALWAYS) != 0) - action |= SSQ_PRINT_SENSE; - else if ((sense_flags & SF_NO_PRINT) != 0) - action &= ~SSQ_PRINT_SENSE; - - return (action); -} - -/* - * Try make as good a match as possible with - * available sub drivers - */ -int -aic_inquiry_match(caddr_t inqbuffer, caddr_t table_entry) -{ - struct scsi_inquiry_pattern *entry; - struct scsi_inquiry_data *inq; - - entry = (struct scsi_inquiry_pattern *)table_entry; - inq = (struct scsi_inquiry_data *)inqbuffer; - - if (((SID_TYPE(inq) == entry->type) - || (entry->type == T_ANY)) - && (SID_IS_REMOVABLE(inq) ? entry->media_type & SIP_MEDIA_REMOVABLE - : entry->media_type & SIP_MEDIA_FIXED) - && (cam_strmatch(inq->vendor, entry->vendor, sizeof(inq->vendor)) == 0) - && (cam_strmatch(inq->product, entry->product, - sizeof(inq->product)) == 0) - && (cam_strmatch(inq->revision, entry->revision, - sizeof(inq->revision)) == 0)) { - return (0); - } - return (-1); -} /* * Table of syncrates that don't follow the "divisible by 4" @@ -1229,108 +75,6 @@ aic_calc_syncsrate(u_int period_factor) return (10000000 / (period_factor * 4 * 10)); } -/* - * Return speed in KB/s. - */ -u_int -aic_calc_speed(u_int width, u_int period, u_int offset, u_int min_rate) -{ - u_int freq; - - if (offset != 0 && period < min_rate) - freq = aic_calc_syncsrate(period); - else - /* Roughly 3.3MB/s for async */ - freq = 3300; - freq <<= width; - return (freq); -} - -uint32_t -aic_error_action(struct scsi_cmnd *cmd, struct scsi_inquiry_data *inq_data, - cam_status status, u_int scsi_status) -{ - aic_sense_action err_action; - int sense; - - sense = (cmd->result >> 24) == DRIVER_SENSE; - - switch (status) { - case CAM_REQ_CMP: - err_action = SS_NOP; - break; - case CAM_AUTOSENSE_FAIL: - case CAM_SCSI_STATUS_ERROR: - - switch (scsi_status) { - case SCSI_STATUS_OK: - case SCSI_STATUS_COND_MET: - case SCSI_STATUS_INTERMED: - case SCSI_STATUS_INTERMED_COND_MET: - err_action = SS_NOP; - break; - case SCSI_STATUS_CMD_TERMINATED: - case SCSI_STATUS_CHECK_COND: - if (sense != 0) { - struct scsi_sense_data *sense; - - sense = (struct scsi_sense_data *) - &cmd->sense_buffer; - err_action = - aic_sense_error_action(sense, inq_data, 0); - - } else { - err_action = SS_RETRY|SSQ_FALLBACK - | SSQ_DECREMENT_COUNT|EIO; - } - break; - case SCSI_STATUS_QUEUE_FULL: - case SCSI_STATUS_BUSY: - err_action = SS_RETRY|SSQ_DELAY|SSQ_MANY - | SSQ_DECREMENT_COUNT|EBUSY; - break; - case SCSI_STATUS_RESERV_CONFLICT: - default: - err_action = SS_FAIL|EBUSY; - break; - } - break; - case CAM_CMD_TIMEOUT: - case CAM_REQ_CMP_ERR: - case CAM_UNEXP_BUSFREE: - case CAM_UNCOR_PARITY: - case CAM_DATA_RUN_ERR: - err_action = SS_RETRY|SSQ_FALLBACK|EIO; - break; - case CAM_UA_ABORT: - case CAM_UA_TERMIO: - case CAM_MSG_REJECT_REC: - case CAM_SEL_TIMEOUT: - err_action = SS_FAIL|EIO; - break; - case CAM_REQ_INVALID: - case CAM_PATH_INVALID: - case CAM_DEV_NOT_THERE: - case CAM_NO_HBA: - case CAM_PROVIDE_FAIL: - case CAM_REQ_TOO_BIG: - case CAM_RESRC_UNAVAIL: - case CAM_BUSY: - default: - /* panic?? These should never occur in our application. */ - err_action = SS_FAIL|EIO; - break; - case CAM_SCSI_BUS_RESET: - case CAM_BDR_SENT: - case CAM_REQUEUE_REQ: - /* Unconditional requeue */ - err_action = SS_RETRY; - break; - } - - return (err_action); -} - char * aic_parse_brace_option(char *opt_name, char *opt_arg, char *end, int depth, aic_option_callback_t *callback, u_long callback_arg) diff --git a/drivers/scsi/aic7xxx/aiclib.h b/drivers/scsi/aic7xxx/aiclib.h index bfe6f954d3c4..e7d94cbaf2a8 100644 --- a/drivers/scsi/aic7xxx/aiclib.h +++ b/drivers/scsi/aic7xxx/aiclib.h @@ -57,121 +57,6 @@ #ifndef _AICLIB_H #define _AICLIB_H -/* - * Linux Interrupt Support. - */ -#ifndef IRQ_RETVAL -typedef void irqreturn_t; -#define IRQ_RETVAL(x) -#endif - -/* - * SCSI command format - */ - -/* - * Define dome bits that are in ALL (or a lot of) scsi commands - */ -#define SCSI_CTL_LINK 0x01 -#define SCSI_CTL_FLAG 0x02 -#define SCSI_CTL_VENDOR 0xC0 -#define SCSI_CMD_LUN 0xA0 /* these two should not be needed */ -#define SCSI_CMD_LUN_SHIFT 5 /* LUN in the cmd is no longer SCSI */ - -#define SCSI_MAX_CDBLEN 16 /* - * 16 byte commands are in the - * SCSI-3 spec - */ -/* 6byte CDBs special case 0 length to be 256 */ -#define SCSI_CDB6_LEN(len) ((len) == 0 ? 256 : len) - -/* - * This type defines actions to be taken when a particular sense code is - * received. Right now, these flags are only defined to take up 16 bits, - * but can be expanded in the future if necessary. - */ -typedef enum { - SS_NOP = 0x000000, /* Do nothing */ - SS_RETRY = 0x010000, /* Retry the command */ - SS_FAIL = 0x020000, /* Bail out */ - SS_START = 0x030000, /* Send a Start Unit command to the device, - * then retry the original command. - */ - SS_TUR = 0x040000, /* Send a Test Unit Ready command to the - * device, then retry the original command. - */ - SS_REQSENSE = 0x050000, /* Send a RequestSense command to the - * device, then retry the original command. - */ - SS_INQ_REFRESH = 0x060000, - SS_MASK = 0xff0000 -} aic_sense_action; - -typedef enum { - SSQ_NONE = 0x0000, - SSQ_DECREMENT_COUNT = 0x0100, /* Decrement the retry count */ - SSQ_MANY = 0x0200, /* send lots of recovery commands */ - SSQ_RANGE = 0x0400, /* - * This table entry represents the - * end of a range of ASCQs that - * have identical error actions - * and text. - */ - SSQ_PRINT_SENSE = 0x0800, - SSQ_DELAY = 0x1000, /* Delay before retry. */ - SSQ_DELAY_RANDOM = 0x2000, /* Randomized delay before retry. */ - SSQ_FALLBACK = 0x4000, /* Do a speed fallback to recover */ - SSQ_MASK = 0xff00 -} aic_sense_action_qualifier; - -/* Mask for error status values */ -#define SS_ERRMASK 0xff - -/* The default, retyable, error action */ -#define SS_RDEF SS_RETRY|SSQ_DECREMENT_COUNT|SSQ_PRINT_SENSE|EIO - -/* The retyable, error action, with table specified error code */ -#define SS_RET SS_RETRY|SSQ_DECREMENT_COUNT|SSQ_PRINT_SENSE - -/* Fatal error action, with table specified error code */ -#define SS_FATAL SS_FAIL|SSQ_PRINT_SENSE - -struct scsi_generic -{ - uint8_t opcode; - uint8_t bytes[11]; -}; - -struct scsi_request_sense -{ - uint8_t opcode; - uint8_t byte2; - uint8_t unused[2]; - uint8_t length; - uint8_t control; -}; - -struct scsi_test_unit_ready -{ - uint8_t opcode; - uint8_t byte2; - uint8_t unused[3]; - uint8_t control; -}; - -struct scsi_send_diag -{ - uint8_t opcode; - uint8_t byte2; -#define SSD_UOL 0x01 -#define SSD_DOL 0x02 -#define SSD_SELFTEST 0x04 -#define SSD_PF 0x10 - uint8_t unused[1]; - uint8_t paramlen[2]; - uint8_t control; -}; - struct scsi_sense { uint8_t opcode; @@ -181,537 +66,12 @@ struct scsi_sense uint8_t control; }; -struct scsi_inquiry -{ - uint8_t opcode; - uint8_t byte2; -#define SI_EVPD 0x01 - uint8_t page_code; - uint8_t reserved; - uint8_t length; - uint8_t control; -}; - -struct scsi_mode_sense_6 -{ - uint8_t opcode; - uint8_t byte2; -#define SMS_DBD 0x08 - uint8_t page; -#define SMS_PAGE_CODE 0x3F -#define SMS_VENDOR_SPECIFIC_PAGE 0x00 -#define SMS_DISCONNECT_RECONNECT_PAGE 0x02 -#define SMS_PERIPHERAL_DEVICE_PAGE 0x09 -#define SMS_CONTROL_MODE_PAGE 0x0A -#define SMS_ALL_PAGES_PAGE 0x3F -#define SMS_PAGE_CTRL_MASK 0xC0 -#define SMS_PAGE_CTRL_CURRENT 0x00 -#define SMS_PAGE_CTRL_CHANGEABLE 0x40 -#define SMS_PAGE_CTRL_DEFAULT 0x80 -#define SMS_PAGE_CTRL_SAVED 0xC0 - uint8_t unused; - uint8_t length; - uint8_t control; -}; - -struct scsi_mode_sense_10 -{ - uint8_t opcode; - uint8_t byte2; /* same bits as small version */ - uint8_t page; /* same bits as small version */ - uint8_t unused[4]; - uint8_t length[2]; - uint8_t control; -}; - -struct scsi_mode_select_6 -{ - uint8_t opcode; - uint8_t byte2; -#define SMS_SP 0x01 -#define SMS_PF 0x10 - uint8_t unused[2]; - uint8_t length; - uint8_t control; -}; - -struct scsi_mode_select_10 -{ - uint8_t opcode; - uint8_t byte2; /* same bits as small version */ - uint8_t unused[5]; - uint8_t length[2]; - uint8_t control; -}; - -/* - * When sending a mode select to a tape drive, the medium type must be 0. - */ -struct scsi_mode_hdr_6 -{ - uint8_t datalen; - uint8_t medium_type; - uint8_t dev_specific; - uint8_t block_descr_len; -}; - -struct scsi_mode_hdr_10 -{ - uint8_t datalen[2]; - uint8_t medium_type; - uint8_t dev_specific; - uint8_t reserved[2]; - uint8_t block_descr_len[2]; -}; - -struct scsi_mode_block_descr -{ - uint8_t density_code; - uint8_t num_blocks[3]; - uint8_t reserved; - uint8_t block_len[3]; -}; - -struct scsi_log_sense -{ - uint8_t opcode; - uint8_t byte2; -#define SLS_SP 0x01 -#define SLS_PPC 0x02 - uint8_t page; -#define SLS_PAGE_CODE 0x3F -#define SLS_ALL_PAGES_PAGE 0x00 -#define SLS_OVERRUN_PAGE 0x01 -#define SLS_ERROR_WRITE_PAGE 0x02 -#define SLS_ERROR_READ_PAGE 0x03 -#define SLS_ERROR_READREVERSE_PAGE 0x04 -#define SLS_ERROR_VERIFY_PAGE 0x05 -#define SLS_ERROR_NONMEDIUM_PAGE 0x06 -#define SLS_ERROR_LASTN_PAGE 0x07 -#define SLS_PAGE_CTRL_MASK 0xC0 -#define SLS_PAGE_CTRL_THRESHOLD 0x00 -#define SLS_PAGE_CTRL_CUMULATIVE 0x40 -#define SLS_PAGE_CTRL_THRESH_DEFAULT 0x80 -#define SLS_PAGE_CTRL_CUMUL_DEFAULT 0xC0 - uint8_t reserved[2]; - uint8_t paramptr[2]; - uint8_t length[2]; - uint8_t control; -}; - -struct scsi_log_select -{ - uint8_t opcode; - uint8_t byte2; -/* SLS_SP 0x01 */ -#define SLS_PCR 0x02 - uint8_t page; -/* SLS_PAGE_CTRL_MASK 0xC0 */ -/* SLS_PAGE_CTRL_THRESHOLD 0x00 */ -/* SLS_PAGE_CTRL_CUMULATIVE 0x40 */ -/* SLS_PAGE_CTRL_THRESH_DEFAULT 0x80 */ -/* SLS_PAGE_CTRL_CUMUL_DEFAULT 0xC0 */ - uint8_t reserved[4]; - uint8_t length[2]; - uint8_t control; -}; - -struct scsi_log_header -{ - uint8_t page; - uint8_t reserved; - uint8_t datalen[2]; -}; - -struct scsi_log_param_header { - uint8_t param_code[2]; - uint8_t param_control; -#define SLP_LP 0x01 -#define SLP_LBIN 0x02 -#define SLP_TMC_MASK 0x0C -#define SLP_TMC_ALWAYS 0x00 -#define SLP_TMC_EQUAL 0x04 -#define SLP_TMC_NOTEQUAL 0x08 -#define SLP_TMC_GREATER 0x0C -#define SLP_ETC 0x10 -#define SLP_TSD 0x20 -#define SLP_DS 0x40 -#define SLP_DU 0x80 - uint8_t param_len; -}; - -struct scsi_control_page { - uint8_t page_code; - uint8_t page_length; - uint8_t rlec; -#define SCB_RLEC 0x01 /*Report Log Exception Cond*/ - uint8_t queue_flags; -#define SCP_QUEUE_ALG_MASK 0xF0 -#define SCP_QUEUE_ALG_RESTRICTED 0x00 -#define SCP_QUEUE_ALG_UNRESTRICTED 0x10 -#define SCP_QUEUE_ERR 0x02 /*Queued I/O aborted for CACs*/ -#define SCP_QUEUE_DQUE 0x01 /*Queued I/O disabled*/ - uint8_t eca_and_aen; -#define SCP_EECA 0x80 /*Enable Extended CA*/ -#define SCP_RAENP 0x04 /*Ready AEN Permission*/ -#define SCP_UAAENP 0x02 /*UA AEN Permission*/ -#define SCP_EAENP 0x01 /*Error AEN Permission*/ - uint8_t reserved; - uint8_t aen_holdoff_period[2]; -}; - -struct scsi_reserve -{ - uint8_t opcode; - uint8_t byte2; - uint8_t unused[2]; - uint8_t length; - uint8_t control; -}; - -struct scsi_release -{ - uint8_t opcode; - uint8_t byte2; - uint8_t unused[2]; - uint8_t length; - uint8_t control; -}; - -struct scsi_prevent -{ - uint8_t opcode; - uint8_t byte2; - uint8_t unused[2]; - uint8_t how; - uint8_t control; -}; -#define PR_PREVENT 0x01 -#define PR_ALLOW 0x00 - -struct scsi_sync_cache -{ - uint8_t opcode; - uint8_t byte2; - uint8_t begin_lba[4]; - uint8_t reserved; - uint8_t lb_count[2]; - uint8_t control; -}; - - -struct scsi_changedef -{ - uint8_t opcode; - uint8_t byte2; - uint8_t unused1; - uint8_t how; - uint8_t unused[4]; - uint8_t datalen; - uint8_t control; -}; - -struct scsi_read_buffer -{ - uint8_t opcode; - uint8_t byte2; -#define RWB_MODE 0x07 -#define RWB_MODE_HDR_DATA 0x00 -#define RWB_MODE_DATA 0x02 -#define RWB_MODE_DOWNLOAD 0x04 -#define RWB_MODE_DOWNLOAD_SAVE 0x05 - uint8_t buffer_id; - uint8_t offset[3]; - uint8_t length[3]; - uint8_t control; -}; - -struct scsi_write_buffer -{ - uint8_t opcode; - uint8_t byte2; - uint8_t buffer_id; - uint8_t offset[3]; - uint8_t length[3]; - uint8_t control; -}; - -struct scsi_rw_6 -{ - uint8_t opcode; - uint8_t addr[3]; -/* only 5 bits are valid in the MSB address byte */ -#define SRW_TOPADDR 0x1F - uint8_t length; - uint8_t control; -}; - -struct scsi_rw_10 -{ - uint8_t opcode; -#define SRW10_RELADDR 0x01 -#define SRW10_FUA 0x08 -#define SRW10_DPO 0x10 - uint8_t byte2; - uint8_t addr[4]; - uint8_t reserved; - uint8_t length[2]; - uint8_t control; -}; - -struct scsi_rw_12 -{ - uint8_t opcode; -#define SRW12_RELADDR 0x01 -#define SRW12_FUA 0x08 -#define SRW12_DPO 0x10 - uint8_t byte2; - uint8_t addr[4]; - uint8_t length[4]; - uint8_t reserved; - uint8_t control; -}; - -struct scsi_start_stop_unit -{ - uint8_t opcode; - uint8_t byte2; -#define SSS_IMMED 0x01 - uint8_t reserved[2]; - uint8_t how; -#define SSS_START 0x01 -#define SSS_LOEJ 0x02 - uint8_t control; -}; - -#define SC_SCSI_1 0x01 -#define SC_SCSI_2 0x03 - -/* - * Opcodes - */ - -#define TEST_UNIT_READY 0x00 -#define REQUEST_SENSE 0x03 -#define READ_6 0x08 -#define WRITE_6 0x0a -#define INQUIRY 0x12 -#define MODE_SELECT_6 0x15 -#define MODE_SENSE_6 0x1a -#define START_STOP_UNIT 0x1b -#define START_STOP 0x1b -#define RESERVE 0x16 -#define RELEASE 0x17 -#define RECEIVE_DIAGNOSTIC 0x1c -#define SEND_DIAGNOSTIC 0x1d -#define PREVENT_ALLOW 0x1e -#define READ_CAPACITY 0x25 -#define READ_10 0x28 -#define WRITE_10 0x2a -#define POSITION_TO_ELEMENT 0x2b -#define SYNCHRONIZE_CACHE 0x35 -#define WRITE_BUFFER 0x3b -#define READ_BUFFER 0x3c -#define CHANGE_DEFINITION 0x40 -#define LOG_SELECT 0x4c -#define LOG_SENSE 0x4d -#ifdef XXXCAM -#define MODE_SENSE_10 0x5A -#endif -#define MODE_SELECT_10 0x55 -#define MOVE_MEDIUM 0xa5 -#define READ_12 0xa8 -#define WRITE_12 0xaa -#define READ_ELEMENT_STATUS 0xb8 - - -/* - * Device Types - */ -#define T_DIRECT 0x00 -#define T_SEQUENTIAL 0x01 -#define T_PRINTER 0x02 -#define T_PROCESSOR 0x03 -#define T_WORM 0x04 -#define T_CDROM 0x05 -#define T_SCANNER 0x06 -#define T_OPTICAL 0x07 -#define T_CHANGER 0x08 -#define T_COMM 0x09 -#define T_ASC0 0x0a -#define T_ASC1 0x0b -#define T_STORARRAY 0x0c -#define T_ENCLOSURE 0x0d -#define T_RBC 0x0e -#define T_OCRW 0x0f -#define T_NODEVICE 0x1F -#define T_ANY 0xFF /* Used in Quirk table matches */ - -#define T_REMOV 1 -#define T_FIXED 0 - -/* - * This length is the initial inquiry length used by the probe code, as - * well as the legnth necessary for aic_print_inquiry() to function - * correctly. If either use requires a different length in the future, - * the two values should be de-coupled. - */ -#define SHORT_INQUIRY_LENGTH 36 - -struct scsi_inquiry_data -{ - uint8_t device; -#define SID_TYPE(inq_data) ((inq_data)->device & 0x1f) -#define SID_QUAL(inq_data) (((inq_data)->device & 0xE0) >> 5) -#define SID_QUAL_LU_CONNECTED 0x00 /* - * The specified peripheral device - * type is currently connected to - * logical unit. If the target cannot - * determine whether or not a physical - * device is currently connected, it - * shall also use this peripheral - * qualifier when returning the INQUIRY - * data. This peripheral qualifier - * does not mean that the device is - * ready for access by the initiator. - */ -#define SID_QUAL_LU_OFFLINE 0x01 /* - * The target is capable of supporting - * the specified peripheral device type - * on this logical unit; however, the - * physical device is not currently - * connected to this logical unit. - */ -#define SID_QUAL_RSVD 0x02 -#define SID_QUAL_BAD_LU 0x03 /* - * The target is not capable of - * supporting a physical device on - * this logical unit. For this - * peripheral qualifier the peripheral - * device type shall be set to 1Fh to - * provide compatibility with previous - * versions of SCSI. All other - * peripheral device type values are - * reserved for this peripheral - * qualifier. - */ -#define SID_QUAL_IS_VENDOR_UNIQUE(inq_data) ((SID_QUAL(inq_data) & 0x08) != 0) - uint8_t dev_qual2; -#define SID_QUAL2 0x7F -#define SID_IS_REMOVABLE(inq_data) (((inq_data)->dev_qual2 & 0x80) != 0) - uint8_t version; -#define SID_ANSI_REV(inq_data) ((inq_data)->version & 0x07) #define SCSI_REV_0 0 #define SCSI_REV_CCS 1 #define SCSI_REV_2 2 #define SCSI_REV_SPC 3 #define SCSI_REV_SPC2 4 -#define SID_ECMA 0x38 -#define SID_ISO 0xC0 - uint8_t response_format; -#define SID_AENC 0x80 -#define SID_TrmIOP 0x40 - uint8_t additional_length; - uint8_t reserved[2]; - uint8_t flags; -#define SID_SftRe 0x01 -#define SID_CmdQue 0x02 -#define SID_Linked 0x08 -#define SID_Sync 0x10 -#define SID_WBus16 0x20 -#define SID_WBus32 0x40 -#define SID_RelAdr 0x80 -#define SID_VENDOR_SIZE 8 - char vendor[SID_VENDOR_SIZE]; -#define SID_PRODUCT_SIZE 16 - char product[SID_PRODUCT_SIZE]; -#define SID_REVISION_SIZE 4 - char revision[SID_REVISION_SIZE]; - /* - * The following fields were taken from SCSI Primary Commands - 2 - * (SPC-2) Revision 14, Dated 11 November 1999 - */ -#define SID_VENDOR_SPECIFIC_0_SIZE 20 - uint8_t vendor_specific0[SID_VENDOR_SPECIFIC_0_SIZE]; - /* - * An extension of SCSI Parallel Specific Values - */ -#define SID_SPI_IUS 0x01 -#define SID_SPI_QAS 0x02 -#define SID_SPI_CLOCK_ST 0x00 -#define SID_SPI_CLOCK_DT 0x04 -#define SID_SPI_CLOCK_DT_ST 0x0C -#define SID_SPI_MASK 0x0F - uint8_t spi3data; - uint8_t reserved2; - /* - * Version Descriptors, stored 2 byte values. - */ - uint8_t version1[2]; - uint8_t version2[2]; - uint8_t version3[2]; - uint8_t version4[2]; - uint8_t version5[2]; - uint8_t version6[2]; - uint8_t version7[2]; - uint8_t version8[2]; - - uint8_t reserved3[22]; - -#define SID_VENDOR_SPECIFIC_1_SIZE 160 - uint8_t vendor_specific1[SID_VENDOR_SPECIFIC_1_SIZE]; -}; - -struct scsi_vpd_unit_serial_number -{ - uint8_t device; - uint8_t page_code; -#define SVPD_UNIT_SERIAL_NUMBER 0x80 - uint8_t reserved; - uint8_t length; /* serial number length */ -#define SVPD_SERIAL_NUM_SIZE 251 - uint8_t serial_num[SVPD_SERIAL_NUM_SIZE]; -}; - -struct scsi_read_capacity -{ - uint8_t opcode; - uint8_t byte2; - uint8_t addr[4]; - uint8_t unused[3]; - uint8_t control; -}; - -struct scsi_read_capacity_data -{ - uint8_t addr[4]; - uint8_t length[4]; -}; - -struct scsi_report_luns -{ - uint8_t opcode; - uint8_t byte2; - uint8_t unused[3]; - uint8_t addr[4]; - uint8_t control; -}; - -struct scsi_report_luns_data { - uint8_t length[4]; /* length of LUN inventory, in bytes */ - uint8_t reserved[4]; /* unused */ - /* - * LUN inventory- we only support the type zero form for now. - */ - struct { - uint8_t lundata[8]; - } luns[1]; -}; -#define RPL_LUNDATA_ATYP_MASK 0xc0 /* MBZ for type 0 lun */ -#define RPL_LUNDATA_T0LUN 1 /* @ lundata[1] */ - - struct scsi_sense_data { uint8_t error_code; @@ -757,41 +117,6 @@ struct scsi_sense_data #define SSD_FULL_SIZE sizeof(struct scsi_sense_data) }; -struct scsi_mode_header_6 -{ - uint8_t data_length; /* Sense data length */ - uint8_t medium_type; - uint8_t dev_spec; - uint8_t blk_desc_len; -}; - -struct scsi_mode_header_10 -{ - uint8_t data_length[2];/* Sense data length */ - uint8_t medium_type; - uint8_t dev_spec; - uint8_t unused[2]; - uint8_t blk_desc_len[2]; -}; - -struct scsi_mode_page_header -{ - uint8_t page_code; - uint8_t page_length; -}; - -struct scsi_mode_blk_desc -{ - uint8_t density; - uint8_t nblocks[3]; - uint8_t reserved; - uint8_t blklen[3]; -}; - -#define SCSI_DEFAULT_DENSITY 0x00 /* use 'default' density */ -#define SCSI_SAME_DENSITY 0x7f /* use 'same' density- >= SCSI-2 only */ - - /* * Status Byte */ @@ -807,76 +132,7 @@ struct scsi_mode_blk_desc #define SCSI_STATUS_ACA_ACTIVE 0x30 #define SCSI_STATUS_TASK_ABORTED 0x40 -struct scsi_inquiry_pattern { - uint8_t type; - uint8_t media_type; -#define SIP_MEDIA_REMOVABLE 0x01 -#define SIP_MEDIA_FIXED 0x02 - const char *vendor; - const char *product; - const char *revision; -}; - -struct scsi_static_inquiry_pattern { - uint8_t type; - uint8_t media_type; - char vendor[SID_VENDOR_SIZE+1]; - char product[SID_PRODUCT_SIZE+1]; - char revision[SID_REVISION_SIZE+1]; -}; - -struct scsi_sense_quirk_entry { - struct scsi_inquiry_pattern inq_pat; - int num_sense_keys; - int num_ascs; - struct sense_key_table_entry *sense_key_info; - struct asc_table_entry *asc_info; -}; - -struct sense_key_table_entry { - uint8_t sense_key; - uint32_t action; - const char *desc; -}; - -struct asc_table_entry { - uint8_t asc; - uint8_t ascq; - uint32_t action; - const char *desc; -}; - -struct op_table_entry { - uint8_t opcode; - uint16_t opmask; - const char *desc; -}; - -struct scsi_op_quirk_entry { - struct scsi_inquiry_pattern inq_pat; - int num_ops; - struct op_table_entry *op_table; -}; - -typedef enum { - SSS_FLAG_NONE = 0x00, - SSS_FLAG_PRINT_COMMAND = 0x01 -} scsi_sense_string_flags; - -extern const char *scsi_sense_key_text[]; - /************************* Large Disk Handling ********************************/ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) -static __inline int aic_sector_div(u_long capacity, int heads, int sectors); - -static __inline int -aic_sector_div(u_long capacity, int heads, int sectors) -{ - return (capacity / (heads * sectors)); -} -#else -static __inline int aic_sector_div(sector_t capacity, int heads, int sectors); - static __inline int aic_sector_div(sector_t capacity, int heads, int sectors) { @@ -884,7 +140,6 @@ aic_sector_div(sector_t capacity, int heads, int sectors) sector_div(capacity, (heads * sectors)); return (int)capacity; } -#endif /**************************** Module Library Hack *****************************/ /* @@ -899,138 +154,15 @@ aic_sector_div(sector_t capacity, int heads, int sectors) #define AIC_LIB_ENTRY_EXPAND(x, prefix) AIC_LIB_ENTRY_CONCAT(x, prefix) #define AIC_LIB_ENTRY(x) AIC_LIB_ENTRY_EXPAND(x, AIC_LIB_PREFIX) -#define aic_sense_desc AIC_LIB_ENTRY(_sense_desc) -#define aic_sense_error_action AIC_LIB_ENTRY(_sense_error_action) -#define aic_error_action AIC_LIB_ENTRY(_error_action) -#define aic_op_desc AIC_LIB_ENTRY(_op_desc) -#define aic_cdb_string AIC_LIB_ENTRY(_cdb_string) -#define aic_print_inquiry AIC_LIB_ENTRY(_print_inquiry) #define aic_calc_syncsrate AIC_LIB_ENTRY(_calc_syncrate) -#define aic_calc_syncparam AIC_LIB_ENTRY(_calc_syncparam) -#define aic_calc_speed AIC_LIB_ENTRY(_calc_speed) -#define aic_inquiry_match AIC_LIB_ENTRY(_inquiry_match) -#define aic_static_inquiry_match AIC_LIB_ENTRY(_static_inquiry_match) -#define aic_parse_brace_option AIC_LIB_ENTRY(_parse_brace_option) - -/******************************************************************************/ - -void aic_sense_desc(int /*sense_key*/, int /*asc*/, - int /*ascq*/, struct scsi_inquiry_data*, - const char** /*sense_key_desc*/, - const char** /*asc_desc*/); -aic_sense_action aic_sense_error_action(struct scsi_sense_data*, - struct scsi_inquiry_data*, - uint32_t /*sense_flags*/); -uint32_t aic_error_action(struct scsi_cmnd *, - struct scsi_inquiry_data *, - cam_status, u_int); - -#define SF_RETRY_UA 0x01 -#define SF_NO_PRINT 0x02 -#define SF_QUIET_IR 0x04 /* Be quiet about Illegal Request reponses */ -#define SF_PRINT_ALWAYS 0x08 - - -const char * aic_op_desc(uint16_t /*opcode*/, struct scsi_inquiry_data*); -char * aic_cdb_string(uint8_t* /*cdb_ptr*/, char* /*cdb_string*/, - size_t /*len*/); -void aic_print_inquiry(struct scsi_inquiry_data*); u_int aic_calc_syncsrate(u_int /*period_factor*/); -u_int aic_calc_syncparam(u_int /*period*/); -u_int aic_calc_speed(u_int width, u_int period, u_int offset, - u_int min_rate); - -int aic_inquiry_match(caddr_t /*inqbuffer*/, - caddr_t /*table_entry*/); -int aic_static_inquiry_match(caddr_t /*inqbuffer*/, - caddr_t /*table_entry*/); typedef void aic_option_callback_t(u_long, int, int, int32_t); char * aic_parse_brace_option(char *opt_name, char *opt_arg, char *end, int depth, aic_option_callback_t *, u_long); -static __inline void scsi_extract_sense(struct scsi_sense_data *sense, - int *error_code, int *sense_key, - int *asc, int *ascq); -static __inline void scsi_ulto2b(uint32_t val, uint8_t *bytes); -static __inline void scsi_ulto3b(uint32_t val, uint8_t *bytes); -static __inline void scsi_ulto4b(uint32_t val, uint8_t *bytes); -static __inline uint32_t scsi_2btoul(uint8_t *bytes); -static __inline uint32_t scsi_3btoul(uint8_t *bytes); -static __inline int32_t scsi_3btol(uint8_t *bytes); -static __inline uint32_t scsi_4btoul(uint8_t *bytes); - -static __inline void scsi_extract_sense(struct scsi_sense_data *sense, - int *error_code, int *sense_key, - int *asc, int *ascq) -{ - *error_code = sense->error_code & SSD_ERRCODE; - *sense_key = sense->flags & SSD_KEY; - *asc = (sense->extra_len >= 5) ? sense->add_sense_code : 0; - *ascq = (sense->extra_len >= 6) ? sense->add_sense_code_qual : 0; -} - -static __inline void -scsi_ulto2b(uint32_t val, uint8_t *bytes) -{ - - bytes[0] = (val >> 8) & 0xff; - bytes[1] = val & 0xff; -} - -static __inline void -scsi_ulto3b(uint32_t val, uint8_t *bytes) -{ - - bytes[0] = (val >> 16) & 0xff; - bytes[1] = (val >> 8) & 0xff; - bytes[2] = val & 0xff; -} - -static __inline void -scsi_ulto4b(uint32_t val, uint8_t *bytes) -{ - - bytes[0] = (val >> 24) & 0xff; - bytes[1] = (val >> 16) & 0xff; - bytes[2] = (val >> 8) & 0xff; - bytes[3] = val & 0xff; -} - -static __inline uint32_t -scsi_2btoul(uint8_t *bytes) -{ - uint32_t rv; - - rv = (bytes[0] << 8) | - bytes[1]; - return (rv); -} - -static __inline uint32_t -scsi_3btoul(uint8_t *bytes) -{ - uint32_t rv; - - rv = (bytes[0] << 16) | - (bytes[1] << 8) | - bytes[2]; - return (rv); -} - -static __inline int32_t -scsi_3btol(uint8_t *bytes) -{ - uint32_t rc = scsi_3btoul(bytes); - - if (rc & 0x00800000) - rc |= 0xff000000; - - return (int32_t) rc; -} - static __inline uint32_t scsi_4btoul(uint8_t *bytes) { From e537a36d528053f6b9dbe6c88e763e835c0d3517 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sun, 5 Jun 2005 02:07:14 -0500 Subject: [PATCH 063/114] [SCSI] use scatter lists for all block pc requests and simplify hw handlers Here's the proof of concept for this one. It converts scsi_wait_req to do correct REQ_BLOCK_PC submission (and works nicely in my setup). The final goal should be to eliminate struct scsi_request, but that can't be done until the character submission paths of sg and st are also modified. There's some loss of functionality to this: retries are no longer controllable (except by setting REQ_FASTFAIL) and the wait_req API needs to be altered, but it looks very nice. Signed-off-by: James Bottomley --- drivers/scsi/scsi_lib.c | 96 +++++++++++++++++++++++++---------------- 1 file changed, 59 insertions(+), 37 deletions(-) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 7a91ca3d32a6..253c1a98d159 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -232,23 +232,6 @@ void scsi_do_req(struct scsi_request *sreq, const void *cmnd, } EXPORT_SYMBOL(scsi_do_req); -static void scsi_wait_done(struct scsi_cmnd *cmd) -{ - struct request *req = cmd->request; - struct request_queue *q = cmd->device->request_queue; - unsigned long flags; - - req->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */ - - spin_lock_irqsave(q->queue_lock, flags); - if (blk_rq_tagged(req)) - blk_queue_end_tag(q, req); - spin_unlock_irqrestore(q->queue_lock, flags); - - if (req->waiting) - complete(req->waiting); -} - /* This is the end routine we get to if a command was never attached * to the request. Simply complete the request without changing * rq_status; this will cause a DRIVER_ERROR. */ @@ -263,19 +246,36 @@ void scsi_wait_req(struct scsi_request *sreq, const void *cmnd, void *buffer, unsigned bufflen, int timeout, int retries) { DECLARE_COMPLETION(wait); - - sreq->sr_request->waiting = &wait; - sreq->sr_request->rq_status = RQ_SCSI_BUSY; - sreq->sr_request->end_io = scsi_wait_req_end_io; - scsi_do_req(sreq, cmnd, buffer, bufflen, scsi_wait_done, - timeout, retries); + struct request *req; + + if (bufflen) + req = blk_rq_map_kern(sreq->sr_device->request_queue, + sreq->sr_data_direction == DMA_TO_DEVICE, + buffer, bufflen, __GFP_WAIT); + else + req = blk_get_request(sreq->sr_device->request_queue, READ, + __GFP_WAIT); + req->flags |= REQ_NOMERGE; + req->waiting = &wait; + req->end_io = scsi_wait_req_end_io; + req->cmd_len = COMMAND_SIZE(((u8 *)cmnd)[0]); + req->sense = sreq->sr_sense_buffer; + req->sense_len = 0; + memcpy(req->cmd, cmnd, req->cmd_len); + req->timeout = timeout; + req->flags |= REQ_BLOCK_PC; + req->rq_disk = NULL; + blk_insert_request(sreq->sr_device->request_queue, req, + sreq->sr_data_direction == DMA_TO_DEVICE, NULL); wait_for_completion(&wait); sreq->sr_request->waiting = NULL; - if (sreq->sr_request->rq_status != RQ_SCSI_DONE) + sreq->sr_result = req->errors; + if (req->errors) sreq->sr_result |= (DRIVER_ERROR << 24); - __scsi_release_request(sreq); + blk_put_request(req); } + EXPORT_SYMBOL(scsi_wait_req); /* @@ -878,11 +878,12 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes, return; } if (result) { - printk(KERN_INFO "SCSI error : <%d %d %d %d> return code " - "= 0x%x\n", cmd->device->host->host_no, - cmd->device->channel, - cmd->device->id, - cmd->device->lun, result); + if (!(req->flags & REQ_SPECIAL)) + printk(KERN_INFO "SCSI error : <%d %d %d %d> return code " + "= 0x%x\n", cmd->device->host->host_no, + cmd->device->channel, + cmd->device->id, + cmd->device->lun, result); if (driver_byte(result) & DRIVER_SENSE) scsi_print_sense("", cmd); @@ -1020,6 +1021,12 @@ static int scsi_issue_flush_fn(request_queue_t *q, struct gendisk *disk, return -EOPNOTSUPP; } +static void scsi_generic_done(struct scsi_cmnd *cmd) +{ + BUG_ON(!blk_pc_request(cmd->request)); + scsi_io_completion(cmd, cmd->result == 0 ? cmd->bufflen : 0, 0); +} + static int scsi_prep_fn(struct request_queue *q, struct request *req) { struct scsi_device *sdev = q->queuedata; @@ -1061,7 +1068,7 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req) * these two cases differently. We differentiate by looking * at request->cmd, as this tells us the real story. */ - if (req->flags & REQ_SPECIAL) { + if (req->flags & REQ_SPECIAL && req->special) { struct scsi_request *sreq = req->special; if (sreq->sr_magic == SCSI_REQ_MAGIC) { @@ -1073,7 +1080,7 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req) cmd = req->special; } else if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) { - if(unlikely(specials_only)) { + if(unlikely(specials_only) && !(req->flags & REQ_SPECIAL)) { if(specials_only == SDEV_QUIESCE || specials_only == SDEV_BLOCK) return BLKPREP_DEFER; @@ -1142,11 +1149,26 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req) /* * Initialize the actual SCSI command for this request. */ - drv = *(struct scsi_driver **)req->rq_disk->private_data; - if (unlikely(!drv->init_command(cmd))) { - scsi_release_buffers(cmd); - scsi_put_command(cmd); - return BLKPREP_KILL; + if (req->rq_disk) { + drv = *(struct scsi_driver **)req->rq_disk->private_data; + if (unlikely(!drv->init_command(cmd))) { + scsi_release_buffers(cmd); + scsi_put_command(cmd); + return BLKPREP_KILL; + } + } else { + memcpy(cmd->cmnd, req->cmd, sizeof(cmd->cmnd)); + if (rq_data_dir(req) == WRITE) + cmd->sc_data_direction = DMA_TO_DEVICE; + else if (req->data_len) + cmd->sc_data_direction = DMA_FROM_DEVICE; + else + cmd->sc_data_direction = DMA_NONE; + + cmd->transfersize = req->data_len; + cmd->allowed = 3; + cmd->timeout_per_command = req->timeout; + cmd->done = scsi_generic_done; } } From 8e6401187ef7fb1edc2740832b48bf47ed2c90f2 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Wed, 15 Jun 2005 18:16:09 -0500 Subject: [PATCH 064/114] update scsi_wait_req to new format for blk_rq_map_kern() Signed-off-by: James Bottomley --- drivers/scsi/scsi_lib.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 253c1a98d159..60f07b6a5ffc 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -246,15 +246,18 @@ void scsi_wait_req(struct scsi_request *sreq, const void *cmnd, void *buffer, unsigned bufflen, int timeout, int retries) { DECLARE_COMPLETION(wait); + int write = sreq->sr_data_direction == DMA_TO_DEVICE; struct request *req; - if (bufflen) - req = blk_rq_map_kern(sreq->sr_device->request_queue, - sreq->sr_data_direction == DMA_TO_DEVICE, - buffer, bufflen, __GFP_WAIT); - else - req = blk_get_request(sreq->sr_device->request_queue, READ, - __GFP_WAIT); + req = blk_get_request(sreq->sr_device->request_queue, write, + __GFP_WAIT); + if (bufflen && blk_rq_map_kern(sreq->sr_device->request_queue, req, + buffer, bufflen, __GFP_WAIT)) { + sreq->sr_result = DRIVER_ERROR << 24; + blk_put_request(req); + return; + } + req->flags |= REQ_NOMERGE; req->waiting = &wait; req->end_io = scsi_wait_req_end_io; From 392160335c798bbe94ab3aae6ea0c85d32b81bbc Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Wed, 15 Jun 2005 18:48:29 -0500 Subject: [PATCH 065/114] [SCSI] use scatter lists for all block pc requests and simplify hw handlers Original From: Mike Christie Add scsi_execute_req() as a replacement for scsi_wait_req() Fixed up various pieces (added REQ_SPECIAL and caught req use after free) Signed-off-by: James Bottomley --- drivers/scsi/scsi_lib.c | 51 +++++++++++++++- drivers/scsi/scsi_scan.c | 112 ++++++++++++++++-------------------- include/scsi/scsi_request.h | 3 + 3 files changed, 102 insertions(+), 64 deletions(-) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 60f07b6a5ffc..b8212c563fed 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -246,7 +246,7 @@ void scsi_wait_req(struct scsi_request *sreq, const void *cmnd, void *buffer, unsigned bufflen, int timeout, int retries) { DECLARE_COMPLETION(wait); - int write = sreq->sr_data_direction == DMA_TO_DEVICE; + int write = (sreq->sr_data_direction == DMA_TO_DEVICE); struct request *req; req = blk_get_request(sreq->sr_device->request_queue, write, @@ -281,6 +281,55 @@ void scsi_wait_req(struct scsi_request *sreq, const void *cmnd, void *buffer, EXPORT_SYMBOL(scsi_wait_req); +/** + * scsi_execute_req - insert request and wait for the result + * @sdev: scsi device + * @cmd: scsi command + * @data_direction: data direction + * @buffer: data buffer + * @bufflen: len of buffer + * @sense: optional sense buffer + * @timeout: request timeout in seconds + * @retries: number of times to retry request + * + * scsi_execute_req returns the req->errors value which is the + * the scsi_cmnd result field. + **/ +int scsi_execute_req(struct scsi_device *sdev, unsigned char *cmd, + int data_direction, void *buffer, unsigned bufflen, + unsigned char *sense, int timeout, int retries) +{ + struct request *req; + int write = (data_direction == DMA_TO_DEVICE); + int ret = DRIVER_ERROR << 24; + + req = blk_get_request(sdev->request_queue, write, __GFP_WAIT); + + if (bufflen && blk_rq_map_kern(sdev->request_queue, req, + buffer, bufflen, __GFP_WAIT)) + goto out; + + req->cmd_len = COMMAND_SIZE(cmd[0]); + memcpy(req->cmd, cmd, req->cmd_len); + req->sense = sense; + req->sense_len = 0; + req->timeout = timeout; + req->flags |= REQ_BLOCK_PC | REQ_SPECIAL; + + /* + * head injection *required* here otherwise quiesce won't work + */ + blk_execute_rq(req->q, NULL, req, 1); + + ret = req->errors; + out: + blk_put_request(req); + + return ret; +} + +EXPORT_SYMBOL(scsi_execute_req); + /* * Function: scsi_init_cmd_errh() * diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 48edd67982a5..d2ca4b8fbc13 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -111,15 +111,14 @@ MODULE_PARM_DESC(inq_timeout, /** * scsi_unlock_floptical - unlock device via a special MODE SENSE command - * @sreq: used to send the command + * @sdev: scsi device to send command to * @result: area to store the result of the MODE SENSE * * Description: - * Send a vendor specific MODE SENSE (not a MODE SELECT) command using - * @sreq to unlock a device, storing the (unused) results into result. + * Send a vendor specific MODE SENSE (not a MODE SELECT) command. * Called for BLIST_KEY devices. **/ -static void scsi_unlock_floptical(struct scsi_request *sreq, +static void scsi_unlock_floptical(struct scsi_device *sdev, unsigned char *result) { unsigned char scsi_cmd[MAX_COMMAND_SIZE]; @@ -129,11 +128,10 @@ static void scsi_unlock_floptical(struct scsi_request *sreq, scsi_cmd[1] = 0; scsi_cmd[2] = 0x2e; scsi_cmd[3] = 0; - scsi_cmd[4] = 0x2a; /* size */ + scsi_cmd[4] = 0x2a; /* size */ scsi_cmd[5] = 0; - sreq->sr_cmd_len = 0; - sreq->sr_data_direction = DMA_FROM_DEVICE; - scsi_wait_req(sreq, scsi_cmd, result, 0x2a /* size */, SCSI_TIMEOUT, 3); + scsi_execute_req(sdev, scsi_cmd, DMA_FROM_DEVICE, result, 0x2a, NULL, + SCSI_TIMEOUT, 3); } /** @@ -433,26 +431,26 @@ void scsi_target_reap(struct scsi_target *starget) /** * scsi_probe_lun - probe a single LUN using a SCSI INQUIRY - * @sreq: used to send the INQUIRY + * @sdev: scsi_device to probe * @inq_result: area to store the INQUIRY result + * @result_len: len of inq_result * @bflags: store any bflags found here * * Description: - * Probe the lun associated with @sreq using a standard SCSI INQUIRY; + * Probe the lun associated with @req using a standard SCSI INQUIRY; * - * If the INQUIRY is successful, sreq->sr_result is zero and: the + * If the INQUIRY is successful, zero is returned and the * INQUIRY data is in @inq_result; the scsi_level and INQUIRY length - * are copied to the Scsi_Device at @sreq->sr_device (sdev); - * any flags value is stored in *@bflags. + * are copied to the Scsi_Device any flags value is stored in *@bflags. **/ -static void scsi_probe_lun(struct scsi_request *sreq, char *inq_result, - int *bflags) +static int scsi_probe_lun(struct scsi_device *sdev, char *inq_result, + int result_len, int *bflags) { - struct scsi_device *sdev = sreq->sr_device; /* a bit ugly */ + char sense[SCSI_SENSE_BUFFERSIZE]; unsigned char scsi_cmd[MAX_COMMAND_SIZE]; int first_inquiry_len, try_inquiry_len, next_inquiry_len; int response_len = 0; - int pass, count; + int pass, count, result; struct scsi_sense_hdr sshdr; *bflags = 0; @@ -475,28 +473,28 @@ static void scsi_probe_lun(struct scsi_request *sreq, char *inq_result, memset(scsi_cmd, 0, 6); scsi_cmd[0] = INQUIRY; scsi_cmd[4] = (unsigned char) try_inquiry_len; - sreq->sr_cmd_len = 0; - sreq->sr_data_direction = DMA_FROM_DEVICE; + memset(sense, 0, sizeof(sense)); memset(inq_result, 0, try_inquiry_len); - scsi_wait_req(sreq, (void *) scsi_cmd, (void *) inq_result, - try_inquiry_len, - HZ/2 + HZ*scsi_inq_timeout, 3); + + result = scsi_execute_req(sdev, scsi_cmd, DMA_FROM_DEVICE, + inq_result, try_inquiry_len, sense, + HZ / 2 + HZ * scsi_inq_timeout, 3); SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO "scsi scan: INQUIRY %s " "with code 0x%x\n", - sreq->sr_result ? "failed" : "successful", - sreq->sr_result)); + result ? "failed" : "successful", result)); - if (sreq->sr_result) { + if (result) { /* * not-ready to ready transition [asc/ascq=0x28/0x0] * or power-on, reset [asc/ascq=0x29/0x0], continue. * INQUIRY should not yield UNIT_ATTENTION * but many buggy devices do so anyway. */ - if ((driver_byte(sreq->sr_result) & DRIVER_SENSE) && - scsi_request_normalize_sense(sreq, &sshdr)) { + if ((driver_byte(result) & DRIVER_SENSE) && + scsi_normalize_sense(sense, sizeof(sense), + &sshdr)) { if ((sshdr.sense_key == UNIT_ATTENTION) && ((sshdr.asc == 0x28) || (sshdr.asc == 0x29)) && @@ -507,7 +505,7 @@ static void scsi_probe_lun(struct scsi_request *sreq, char *inq_result, break; } - if (sreq->sr_result == 0) { + if (result == 0) { response_len = (unsigned char) inq_result[4] + 5; if (response_len > 255) response_len = first_inquiry_len; /* sanity */ @@ -556,8 +554,8 @@ static void scsi_probe_lun(struct scsi_request *sreq, char *inq_result, /* If the last transfer attempt got an error, assume the * peripheral doesn't exist or is dead. */ - if (sreq->sr_result) - return; + if (result) + return -EIO; /* Don't report any more data than the device says is valid */ sdev->inquiry_len = min(try_inquiry_len, response_len); @@ -593,7 +591,7 @@ static void scsi_probe_lun(struct scsi_request *sreq, char *inq_result, (sdev->scsi_level == 1 && (inq_result[3] & 0x0f) == 1)) sdev->scsi_level++; - return; + return 0; } /** @@ -800,9 +798,8 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget, void *hostdata) { struct scsi_device *sdev; - struct scsi_request *sreq; unsigned char *result; - int bflags, res = SCSI_SCAN_NO_RESPONSE; + int bflags, res = SCSI_SCAN_NO_RESPONSE, result_len = 256; struct Scsi_Host *shost = dev_to_shost(starget->dev.parent); /* @@ -831,16 +828,13 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget, sdev = scsi_alloc_sdev(starget, lun, hostdata); if (!sdev) goto out; - sreq = scsi_allocate_request(sdev, GFP_ATOMIC); - if (!sreq) - goto out_free_sdev; - result = kmalloc(256, GFP_ATOMIC | + + result = kmalloc(result_len, GFP_ATOMIC | ((shost->unchecked_isa_dma) ? __GFP_DMA : 0)); if (!result) - goto out_free_sreq; + goto out_free_sdev; - scsi_probe_lun(sreq, result, &bflags); - if (sreq->sr_result) + if (scsi_probe_lun(sdev, result, result_len, &bflags)) goto out_free_result; /* @@ -868,7 +862,7 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget, if (res == SCSI_SCAN_LUN_PRESENT) { if (bflags & BLIST_KEY) { sdev->lockable = 0; - scsi_unlock_floptical(sreq, result); + scsi_unlock_floptical(sdev, result); } if (bflagsp) *bflagsp = bflags; @@ -876,8 +870,6 @@ static int scsi_probe_and_add_lun(struct scsi_target *starget, out_free_result: kfree(result); - out_free_sreq: - scsi_release_request(sreq); out_free_sdev: if (res == SCSI_SCAN_LUN_PRESENT) { if (sdevp) { @@ -1065,13 +1057,14 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags, int rescan) { char devname[64]; + char sense[SCSI_SENSE_BUFFERSIZE]; unsigned char scsi_cmd[MAX_COMMAND_SIZE]; unsigned int length; unsigned int lun; unsigned int num_luns; unsigned int retries; + int result; struct scsi_lun *lunp, *lun_data; - struct scsi_request *sreq; u8 *data; struct scsi_sense_hdr sshdr; struct scsi_target *starget = scsi_target(sdev); @@ -1089,10 +1082,6 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags, if (bflags & BLIST_NOLUN) return 0; - sreq = scsi_allocate_request(sdev, GFP_ATOMIC); - if (!sreq) - goto out; - sprintf(devname, "host %d channel %d id %d", sdev->host->host_no, sdev->channel, sdev->id); @@ -1110,7 +1099,7 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags, lun_data = kmalloc(length, GFP_ATOMIC | (sdev->host->unchecked_isa_dma ? __GFP_DMA : 0)); if (!lun_data) - goto out_release_request; + goto out; scsi_cmd[0] = REPORT_LUNS; @@ -1129,8 +1118,6 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags, scsi_cmd[10] = 0; /* reserved */ scsi_cmd[11] = 0; /* control */ - sreq->sr_cmd_len = 0; - sreq->sr_data_direction = DMA_FROM_DEVICE; /* * We can get a UNIT ATTENTION, for example a power on/reset, so @@ -1146,29 +1133,30 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags, SCSI_LOG_SCAN_BUS(3, printk (KERN_INFO "scsi scan: Sending" " REPORT LUNS to %s (try %d)\n", devname, retries)); - scsi_wait_req(sreq, scsi_cmd, lun_data, length, - SCSI_TIMEOUT + 4*HZ, 3); + + memset(sense, 0, sizeof(sense)); + result = scsi_execute_req(sdev, scsi_cmd, DMA_FROM_DEVICE, + lun_data, length, sense, + SCSI_TIMEOUT + 4 * HZ, 3); + SCSI_LOG_SCAN_BUS(3, printk (KERN_INFO "scsi scan: REPORT LUNS" - " %s (try %d) result 0x%x\n", sreq->sr_result - ? "failed" : "successful", retries, - sreq->sr_result)); - if (sreq->sr_result == 0) + " %s (try %d) result 0x%x\n", result + ? "failed" : "successful", retries, result)); + if (result == 0) break; - else if (scsi_request_normalize_sense(sreq, &sshdr)) { + else if (scsi_normalize_sense(sense, sizeof(sense), &sshdr)) { if (sshdr.sense_key != UNIT_ATTENTION) break; } } - if (sreq->sr_result) { + if (result) { /* * The device probably does not support a REPORT LUN command */ kfree(lun_data); - scsi_release_request(sreq); return 1; } - scsi_release_request(sreq); /* * Get the length from the first four bytes of lun_data. @@ -1242,8 +1230,6 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags, kfree(lun_data); return 0; - out_release_request: - scsi_release_request(sreq); out: /* * We are out of memory, don't try scanning any further. diff --git a/include/scsi/scsi_request.h b/include/scsi/scsi_request.h index 98719407d554..d64903a617c3 100644 --- a/include/scsi/scsi_request.h +++ b/include/scsi/scsi_request.h @@ -54,6 +54,9 @@ extern void scsi_do_req(struct scsi_request *, const void *cmnd, void *buffer, unsigned bufflen, void (*done) (struct scsi_cmnd *), int timeout, int retries); +extern int scsi_execute_req(struct scsi_device *sdev, unsigned char *cmd, + int data_direction, void *buffer, unsigned bufflen, + unsigned char *sense, int timeout, int retries); struct scsi_mode_data { __u32 length; From ebd8bb7647e908e8654e565fa289b0300f9f8fa7 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Mon, 15 Aug 2005 16:13:19 -0500 Subject: [PATCH 066/114] [SCSI] fix transport class corner case after rework If your transport class sets the ATTRIBUTE_CONTAINER_NO_CLASSDEVS flag, then its configure method never gets called. This patch fixes that so that the configure method is called with a NULL classdev. Also remove a spurious inverted comma in the transport_class comments. Signed-off-by: James Bottomley --- drivers/base/attribute_container.c | 5 +++++ drivers/base/transport_class.c | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/base/attribute_container.c b/drivers/base/attribute_container.c index 62c093db11e6..ebcae5c34133 100644 --- a/drivers/base/attribute_container.c +++ b/drivers/base/attribute_container.c @@ -237,6 +237,11 @@ attribute_container_device_trigger(struct device *dev, if (!cont->match(cont, dev)) continue; + if (attribute_container_no_classdevs(cont)) { + fn(cont, dev, NULL); + continue; + } + spin_lock(&cont->containers_lock); list_for_each_entry_safe(ic, tmp, &cont->containers, node) { if (dev == ic->classdev.dev) diff --git a/drivers/base/transport_class.c b/drivers/base/transport_class.c index 4fb4c5de8470..f25e7c6b2d27 100644 --- a/drivers/base/transport_class.c +++ b/drivers/base/transport_class.c @@ -7,7 +7,7 @@ * This file is licensed under GPLv2 * * The basic idea here is to allow any "device controller" (which - * would most often be a Host Bus Adapter" to use the services of one + * would most often be a Host Bus Adapter to use the services of one * or more tranport classes for performing transport specific * services. Transport specific services are things that the generic * command layer doesn't want to know about (speed settings, line From 3b2946cc96bfafa90a555c70b2e876cbbd0fae98 Mon Sep 17 00:00:00 2001 From: Mark Haverkamp Date: Mon, 15 Aug 2005 10:50:24 -0700 Subject: [PATCH 067/114] [SCSI] aacraid: Fix aacraid probe breakage (updated) This patch fixes the bad assumption of the aacraid driver with use_sg. I used the 3w-xxxx driver fix as a guide for this. Signed-off-by: Mark Haverkamp Signed-off-by: James Bottomley --- drivers/scsi/aacraid/aachba.c | 79 +++++++++++++++++++++++------------ 1 file changed, 53 insertions(+), 26 deletions(-) diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index 8e3493587299..83bfab73ff65 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -349,6 +349,27 @@ static void aac_io_done(struct scsi_cmnd * scsicmd) spin_unlock_irqrestore(host->host_lock, cpu_flags); } +static void aac_internal_transfer(struct scsi_cmnd *scsicmd, void *data, unsigned int offset, unsigned int len) +{ + void *buf; + unsigned int transfer_len; + struct scatterlist *sg = scsicmd->request_buffer; + + if (scsicmd->use_sg) { + buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset; + transfer_len = min(sg->length, len + offset); + } else { + buf = scsicmd->request_buffer; + transfer_len = min(scsicmd->request_bufflen, len + offset); + } + + memcpy(buf + offset, data, transfer_len - offset); + + if (scsicmd->use_sg) + kunmap_atomic(buf - sg->offset, KM_IRQ0); + +} + static void get_container_name_callback(void *context, struct fib * fibptr) { struct aac_get_name_resp * get_name_reply; @@ -364,18 +385,22 @@ static void get_container_name_callback(void *context, struct fib * fibptr) /* Failure is irrelevant, using default value instead */ if ((le32_to_cpu(get_name_reply->status) == CT_OK) && (get_name_reply->data[0] != '\0')) { - int count; - char * dp; - char * sp = get_name_reply->data; + char *sp = get_name_reply->data; sp[sizeof(((struct aac_get_name_resp *)NULL)->data)-1] = '\0'; while (*sp == ' ') ++sp; - count = sizeof(((struct inquiry_data *)NULL)->inqd_pid); - dp = ((struct inquiry_data *)scsicmd->request_buffer)->inqd_pid; - if (*sp) do { - *dp++ = (*sp) ? *sp++ : ' '; - } while (--count > 0); + if (*sp) { + char d[sizeof(((struct inquiry_data *)NULL)->inqd_pid)]; + int count = sizeof(d); + char *dp = d; + do { + *dp++ = (*sp) ? *sp++ : ' '; + } while (--count > 0); + aac_internal_transfer(scsicmd, d, + offsetof(struct inquiry_data, inqd_pid), sizeof(d)); + } } + scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; fib_complete(fibptr); @@ -1344,44 +1369,45 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) switch (scsicmd->cmnd[0]) { case INQUIRY: { - struct inquiry_data *inq_data_ptr; + struct inquiry_data inq_data; dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", scsicmd->device->id)); - inq_data_ptr = (struct inquiry_data *)scsicmd->request_buffer; - memset(inq_data_ptr, 0, sizeof (struct inquiry_data)); + memset(&inq_data, 0, sizeof (struct inquiry_data)); - inq_data_ptr->inqd_ver = 2; /* claim compliance to SCSI-2 */ - inq_data_ptr->inqd_dtq = 0x80; /* set RMB bit to one indicating that the medium is removable */ - inq_data_ptr->inqd_rdf = 2; /* A response data format value of two indicates that the data shall be in the format specified in SCSI-2 */ - inq_data_ptr->inqd_len = 31; + inq_data.inqd_ver = 2; /* claim compliance to SCSI-2 */ + inq_data.inqd_dtq = 0x80; /* set RMB bit to one indicating that the medium is removable */ + inq_data.inqd_rdf = 2; /* A response data format value of two indicates that the data shall be in the format specified in SCSI-2 */ + inq_data.inqd_len = 31; /*Format for "pad2" is RelAdr | WBus32 | WBus16 | Sync | Linked |Reserved| CmdQue | SftRe */ - inq_data_ptr->inqd_pad2= 0x32 ; /*WBus16|Sync|CmdQue */ + inq_data.inqd_pad2= 0x32 ; /*WBus16|Sync|CmdQue */ /* * Set the Vendor, Product, and Revision Level * see: .c i.e. aac.c */ if (scsicmd->device->id == host->this_id) { - setinqstr(cardtype, (void *) (inq_data_ptr->inqd_vid), (sizeof(container_types)/sizeof(char *))); - inq_data_ptr->inqd_pdt = INQD_PDT_PROC; /* Processor device */ + setinqstr(cardtype, (void *) (inq_data.inqd_vid), (sizeof(container_types)/sizeof(char *))); + inq_data.inqd_pdt = INQD_PDT_PROC; /* Processor device */ + aac_internal_transfer(scsicmd, &inq_data, 0, sizeof(inq_data)); scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; scsicmd->scsi_done(scsicmd); return 0; } - setinqstr(cardtype, (void *) (inq_data_ptr->inqd_vid), fsa_dev_ptr[cid].type); - inq_data_ptr->inqd_pdt = INQD_PDT_DA; /* Direct/random access device */ + setinqstr(cardtype, (void *) (inq_data.inqd_vid), fsa_dev_ptr[cid].type); + inq_data.inqd_pdt = INQD_PDT_DA; /* Direct/random access device */ + aac_internal_transfer(scsicmd, &inq_data, 0, sizeof(inq_data)); return aac_get_container_name(scsicmd, cid); } case READ_CAPACITY: { u32 capacity; - char *cp; + char cp[8]; dprintk((KERN_DEBUG "READ CAPACITY command.\n")); if (fsa_dev_ptr[cid].size <= 0x100000000LL) capacity = fsa_dev_ptr[cid].size - 1; else capacity = (u32)-1; - cp = scsicmd->request_buffer; + cp[0] = (capacity >> 24) & 0xff; cp[1] = (capacity >> 16) & 0xff; cp[2] = (capacity >> 8) & 0xff; @@ -1390,6 +1416,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) cp[5] = 0; cp[6] = 2; cp[7] = 0; + aac_internal_transfer(scsicmd, cp, 0, sizeof(cp)); scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; scsicmd->scsi_done(scsicmd); @@ -1399,15 +1426,15 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) case MODE_SENSE: { - char *mode_buf; + char mode_buf[4]; dprintk((KERN_DEBUG "MODE SENSE command.\n")); - mode_buf = scsicmd->request_buffer; mode_buf[0] = 3; /* Mode data length */ mode_buf[1] = 0; /* Medium type - default */ mode_buf[2] = 0; /* Device-specific param, bit 8: 0/1 = write enabled/protected */ mode_buf[3] = 0; /* Block descriptor length */ + aac_internal_transfer(scsicmd, mode_buf, 0, sizeof(mode_buf)); scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; scsicmd->scsi_done(scsicmd); @@ -1415,10 +1442,9 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) } case MODE_SENSE_10: { - char *mode_buf; + char mode_buf[8]; dprintk((KERN_DEBUG "MODE SENSE 10 byte command.\n")); - mode_buf = scsicmd->request_buffer; mode_buf[0] = 0; /* Mode data length (MSB) */ mode_buf[1] = 6; /* Mode data length (LSB) */ mode_buf[2] = 0; /* Medium type - default */ @@ -1427,6 +1453,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) mode_buf[5] = 0; /* reserved */ mode_buf[6] = 0; /* Block descriptor length (MSB) */ mode_buf[7] = 0; /* Block descriptor length (LSB) */ + aac_internal_transfer(scsicmd, mode_buf, 0, sizeof(mode_buf)); scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD; scsicmd->scsi_done(scsicmd); From be042f240a8528b8f6b741a484cdbbf515698388 Mon Sep 17 00:00:00 2001 From: Dave C Boutcher Date: Mon, 15 Aug 2005 16:52:58 -0500 Subject: [PATCH 068/114] [SCSI] ibmvscsi eh locking With the removal of the spinlocking around eh calls, we need to add a little more locking back in, otherwise we do some naked list manipulation. Signed-off-by: Dave Boutcher Signed-off-by: James Bottomley --- drivers/scsi/ibmvscsi/ibmvscsi.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index fe09d145542a..1ae800ae93d7 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -826,11 +826,13 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd) struct srp_event_struct *tmp_evt, *found_evt; union viosrp_iu srp_rsp; int rsp_rc; + unsigned long flags; u16 lun = lun_from_dev(cmd->device); /* First, find this command in our sent list so we can figure * out the correct tag */ + spin_lock_irqsave(hostdata->host->host_lock, flags); found_evt = NULL; list_for_each_entry(tmp_evt, &hostdata->sent, list) { if (tmp_evt->cmnd == cmd) { @@ -839,11 +841,14 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd) } } - if (!found_evt) + if (!found_evt) { + spin_unlock_irqrestore(hostdata->host->host_lock, flags); return FAILED; + } evt = get_event_struct(&hostdata->pool); if (evt == NULL) { + spin_unlock_irqrestore(hostdata->host->host_lock, flags); printk(KERN_ERR "ibmvscsi: failed to allocate abort event\n"); return FAILED; } @@ -867,7 +872,9 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd) evt->sync_srp = &srp_rsp; init_completion(&evt->comp); - if (ibmvscsi_send_srp_event(evt, hostdata) != 0) { + rsp_rc = ibmvscsi_send_srp_event(evt, hostdata); + spin_unlock_irqrestore(hostdata->host->host_lock, flags); + if (rsp_rc != 0) { printk(KERN_ERR "ibmvscsi: failed to send abort() event\n"); return FAILED; } @@ -901,6 +908,7 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd) * The event is no longer in our list. Make sure it didn't * complete while we were aborting */ + spin_lock_irqsave(hostdata->host->host_lock, flags); found_evt = NULL; list_for_each_entry(tmp_evt, &hostdata->sent, list) { if (tmp_evt->cmnd == cmd) { @@ -910,6 +918,7 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd) } if (found_evt == NULL) { + spin_unlock_irqrestore(hostdata->host->host_lock, flags); printk(KERN_INFO "ibmvscsi: aborted task tag 0x%lx completed\n", tsk_mgmt->managed_task_tag); @@ -924,6 +933,7 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd) list_del(&found_evt->list); unmap_cmd_data(&found_evt->iu.srp.cmd, found_evt->hostdata->dev); free_event_struct(&found_evt->hostdata->pool, found_evt); + spin_unlock_irqrestore(hostdata->host->host_lock, flags); atomic_inc(&hostdata->request_limit); return SUCCESS; } @@ -943,10 +953,13 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd) struct srp_event_struct *tmp_evt, *pos; union viosrp_iu srp_rsp; int rsp_rc; + unsigned long flags; u16 lun = lun_from_dev(cmd->device); + spin_lock_irqsave(hostdata->host->host_lock, flags); evt = get_event_struct(&hostdata->pool); if (evt == NULL) { + spin_unlock_irqrestore(hostdata->host->host_lock, flags); printk(KERN_ERR "ibmvscsi: failed to allocate reset event\n"); return FAILED; } @@ -969,7 +982,9 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd) evt->sync_srp = &srp_rsp; init_completion(&evt->comp); - if (ibmvscsi_send_srp_event(evt, hostdata) != 0) { + rsp_rc = ibmvscsi_send_srp_event(evt, hostdata); + spin_unlock_irqrestore(hostdata->host->host_lock, flags); + if (rsp_rc != 0) { printk(KERN_ERR "ibmvscsi: failed to send reset event\n"); return FAILED; } @@ -1002,6 +1017,7 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd) /* We need to find all commands for this LUN that have not yet been * responded to, and fail them with DID_RESET */ + spin_lock_irqsave(hostdata->host->host_lock, flags); list_for_each_entry_safe(tmp_evt, pos, &hostdata->sent, list) { if ((tmp_evt->cmnd) && (tmp_evt->cmnd->device == cmd->device)) { if (tmp_evt->cmnd) @@ -1017,6 +1033,7 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd) tmp_evt->done(tmp_evt); } } + spin_unlock_irqrestore(hostdata->host->host_lock, flags); return SUCCESS; } From caca1779870b1bcc0fb07e48ebd2403901f356b8 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Tue, 16 Aug 2005 17:26:10 -0500 Subject: [PATCH 069/114] [SCSI] add missing attribute container function prototype attribute_container_classdev_to_container is an exported function of the attribute_container.c file. However, there's no prototype for it. Now I actually want to use it, so add one. Signed-off-by: James Bottomley --- include/linux/attribute_container.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/attribute_container.h b/include/linux/attribute_container.h index f54b05b052b3..ee83fe64a102 100644 --- a/include/linux/attribute_container.h +++ b/include/linux/attribute_container.h @@ -64,6 +64,7 @@ int attribute_container_add_class_device_adapter(struct attribute_container *con struct class_device *classdev); void attribute_container_remove_attrs(struct class_device *classdev); void attribute_container_class_device_del(struct class_device *classdev); +struct attribute_container *attribute_container_classdev_to_container(struct class_device *); struct class_device *attribute_container_find_class_device(struct attribute_container *, struct device *); struct class_device_attribute **attribute_container_classdev_to_attrs(const struct class_device *classdev); From de540a53f2f7b68a48c3021e5ab78ea49f6cf21c Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Sat, 20 Aug 2005 21:27:27 +0200 Subject: [PATCH 070/114] [SCSI] drivers/scsi/constants.c should include scsi_dbg.h C files should include the files with the prototypes for their global functions. Signed-off-by: Adrian Bunk Signed-off-by: James Bottomley --- drivers/scsi/constants.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c index ec161733a82b..0d58d3538bdf 100644 --- a/drivers/scsi/constants.c +++ b/drivers/scsi/constants.c @@ -17,6 +17,7 @@ #include #include #include +#include From 8224bfa84d510630b40ea460b2bb380c91acb8ae Mon Sep 17 00:00:00 2001 From: Dave C Boutcher Date: Mon, 22 Aug 2005 14:38:26 -0500 Subject: [PATCH 071/114] [SCSI] ibmvscsi timeout fix This patch fixes a long term borkenness in ibmvscsi where we were using the wrong timeout field from the scsi command (and using the wrong units.) Now broken by the fact that the scsi_cmnd timeout field is gone entirely. This only worked before because all the SCSI targets assumed that 0 was default. Signed-off-by: Dave Boutcher Signed-off-by: James Bottomley --- drivers/scsi/ibmvscsi/ibmvscsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 1ae800ae93d7..e3e6752c4104 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -594,7 +594,7 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd, init_event_struct(evt_struct, handle_cmd_rsp, VIOSRP_SRP_FORMAT, - cmnd->timeout); + cmnd->timeout_per_command/HZ); evt_struct->cmnd = cmnd; evt_struct->cmnd_done = done; From 51490c89f95b8581782e9baa855da166441852be Mon Sep 17 00:00:00 2001 From: Pete Zaitcev Date: Tue, 5 Jul 2005 18:18:08 -0700 Subject: [PATCH 072/114] [SCSI] sr.c: Fix getting wrong size Here's the problem. Try to do this on 2.6.12: - Kill udev and HAL - Insert a CD-ROM into a SCSI or USB CD-ROM drive - Run dd if=/dev/scd0 - cat /sys/block/sr0/size - Eject the CD, insert a different one - Run dd if=/dev/scd0 This is likely to do "access beyond the end of device", if you let it - cat /sys/block/sr0/size This shows the size of a previous CD, even though dd was supposed to revalidate the device. - Run dd if=/dev/scd0 The second run of dd works correctly! The bug was introduced in 2.5.31, when Al fixes the recursive opens in partitioning. Before, the code worked like this: - Block layer called cdrom_open directly - cdrom_open called sr_open - sr_open called check_disk_change - check_disk_change called sr_media_change - sr_media_change did cd->needs_disk_change=1 - before returning sr_open tested cd->needs_disk_change and called get_sector_size. In 2.6.12, the check_disk_change is called from cdrom_open only. Thus: - Block layer calls sr_bd_open - sr_bd_open calls cdrom_open - cdrom_open calls sr_open - sr_open tests cd->needs_disk_change, which wasn't set yet; returns - cdrom_open calls check_disk_change - check_disk_change calls sr_media_change - sr_media_change does cd->needs_disk_change=1, but nobody cares Acked by: Alexander Viro Signed-off-by: James Bottomley --- drivers/scsi/sr.c | 24 ++---------------------- drivers/scsi/sr.h | 1 - 2 files changed, 2 insertions(+), 23 deletions(-) diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 2f259f249522..f63d8c6c2a33 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -199,15 +199,7 @@ int sr_media_change(struct cdrom_device_info *cdi, int slot) /* check multisession offset etc */ sr_cd_check(cdi); - /* - * If the disk changed, the capacity will now be different, - * so we force a re-read of this information - * Force 2048 for the sector size so that filesystems won't - * be trying to use something that is too small if the disc - * has changed. - */ - cd->needs_sector_size = 1; - cd->device->sector_size = 2048; + get_sectorsize(cd); } return retval; } @@ -538,13 +530,6 @@ static int sr_open(struct cdrom_device_info *cdi, int purpose) if (!scsi_block_when_processing_errors(sdev)) goto error_out; - /* - * If this device did not have media in the drive at boot time, then - * we would have been unable to get the sector size. Check to see if - * this is the case, and try again. - */ - if (cd->needs_sector_size) - get_sectorsize(cd); return 0; error_out: @@ -604,7 +589,6 @@ static int sr_probe(struct device *dev) cd->driver = &sr_template; cd->disk = disk; cd->capacity = 0x1fffff; - cd->needs_sector_size = 1; cd->device->changed = 1; /* force recheck CD type */ cd->use = 1; cd->readcd_known = 0; @@ -694,7 +678,6 @@ static void get_sectorsize(struct scsi_cd *cd) if (the_result) { cd->capacity = 0x1fffff; sector_size = 2048; /* A guess, just in case */ - cd->needs_sector_size = 1; } else { #if 0 if (cdrom_get_last_written(&cd->cdi, @@ -727,7 +710,6 @@ static void get_sectorsize(struct scsi_cd *cd) printk("%s: unsupported sector size %d.\n", cd->cdi.name, sector_size); cd->capacity = 0; - cd->needs_sector_size = 1; } cd->device->sector_size = sector_size; @@ -736,7 +718,6 @@ static void get_sectorsize(struct scsi_cd *cd) * Add this so that we have the ability to correctly gauge * what the device is capable of. */ - cd->needs_sector_size = 0; set_capacity(cd->disk, cd->capacity); } @@ -748,8 +729,7 @@ static void get_sectorsize(struct scsi_cd *cd) Enomem: cd->capacity = 0x1fffff; - sector_size = 2048; /* A guess, just in case */ - cd->needs_sector_size = 1; + cd->device->sector_size = 2048; /* A guess, just in case */ if (SRpnt) scsi_release_request(SRpnt); goto out; diff --git a/drivers/scsi/sr.h b/drivers/scsi/sr.h index 0b3178007203..d2bcd99c272f 100644 --- a/drivers/scsi/sr.h +++ b/drivers/scsi/sr.h @@ -33,7 +33,6 @@ typedef struct scsi_cd { struct scsi_device *device; unsigned int vendor; /* vendor code, see sr_vendor.c */ unsigned long ms_offset; /* for reading multisession-CD's */ - unsigned needs_sector_size:1; /* needs to get sector size */ unsigned use:1; /* is this device still supportable */ unsigned xa_flag:1; /* CD has XA sectors ? */ unsigned readcd_known:1; /* drive supports READ_CD (0xbe) */ From 1cf72699c1530c3e4ac3d58344f6a6a40a2f46d3 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sun, 28 Aug 2005 11:27:01 -0500 Subject: [PATCH 073/114] [SCSI] convert the remaining mid-layer pieces to scsi_execute_req After this, we just have some drivers, all the ULDs and the SPI transport class using scsi_wait_req(). Signed-off-by: James Bottomley --- drivers/scsi/scsi_ioctl.c | 46 +++++++----------- drivers/scsi/scsi_lib.c | 94 +++++++++++++------------------------ drivers/scsi/sd.c | 5 +- drivers/scsi/sr.c | 2 +- include/scsi/scsi_device.h | 13 ++++- include/scsi/scsi_request.h | 15 ------ 6 files changed, 64 insertions(+), 111 deletions(-) diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index f5bf5c07be91..5f399c9c68ee 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c @@ -88,25 +88,21 @@ static int ioctl_probe(struct Scsi_Host *host, void __user *buffer) static int ioctl_internal_command(struct scsi_device *sdev, char *cmd, int timeout, int retries) { - struct scsi_request *sreq; int result; struct scsi_sense_hdr sshdr; + char sense[SCSI_SENSE_BUFFERSIZE]; SCSI_LOG_IOCTL(1, printk("Trying ioctl with scsi command %d\n", *cmd)); - sreq = scsi_allocate_request(sdev, GFP_KERNEL); - if (!sreq) { - printk(KERN_WARNING "SCSI internal ioctl failed, no memory\n"); - return -ENOMEM; - } - sreq->sr_data_direction = DMA_NONE; - scsi_wait_req(sreq, cmd, NULL, 0, timeout, retries); + memset(sense, 0, sizeof(*sense)); + result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, + sense, timeout, retries); - SCSI_LOG_IOCTL(2, printk("Ioctl returned 0x%x\n", sreq->sr_result)); + SCSI_LOG_IOCTL(2, printk("Ioctl returned 0x%x\n", result)); - if ((driver_byte(sreq->sr_result) & DRIVER_SENSE) && - (scsi_request_normalize_sense(sreq, &sshdr))) { + if ((driver_byte(result) & DRIVER_SENSE) && + (scsi_normalize_sense(sense, sizeof(*sense), &sshdr))) { switch (sshdr.sense_key) { case ILLEGAL_REQUEST: if (cmd[0] == ALLOW_MEDIUM_REMOVAL) @@ -125,7 +121,7 @@ static int ioctl_internal_command(struct scsi_device *sdev, char *cmd, case UNIT_ATTENTION: if (sdev->removable) { sdev->changed = 1; - sreq->sr_result = 0; /* This is no longer considered an error */ + result = 0; /* This is no longer considered an error */ break; } default: /* Fall through for non-removable media */ @@ -135,15 +131,13 @@ static int ioctl_internal_command(struct scsi_device *sdev, char *cmd, sdev->channel, sdev->id, sdev->lun, - sreq->sr_result); - scsi_print_req_sense(" ", sreq); + result); + __scsi_print_sense(" ", sense, sizeof(*sense)); break; } } - result = sreq->sr_result; SCSI_LOG_IOCTL(2, printk("IOCTL Releasing command\n")); - scsi_release_request(sreq); return result; } @@ -208,8 +202,8 @@ int scsi_ioctl_send_command(struct scsi_device *sdev, { char *buf; unsigned char cmd[MAX_COMMAND_SIZE]; + unsigned char sense[SCSI_SENSE_BUFFERSIZE]; char __user *cmd_in; - struct scsi_request *sreq; unsigned char opcode; unsigned int inlen, outlen, cmdlen; unsigned int needed, buf_needed; @@ -321,31 +315,23 @@ int scsi_ioctl_send_command(struct scsi_device *sdev, break; } - sreq = scsi_allocate_request(sdev, GFP_KERNEL); - if (!sreq) { - result = -EINTR; - goto error; - } - - sreq->sr_data_direction = data_direction; - scsi_wait_req(sreq, cmd, buf, needed, timeout, retries); - + result = scsi_execute_req(sdev, cmd, data_direction, buf, needed, + sense, timeout, retries); + /* * If there was an error condition, pass the info back to the user. */ - result = sreq->sr_result; if (result) { - int sb_len = sizeof(sreq->sr_sense_buffer); + int sb_len = sizeof(*sense); sb_len = (sb_len > OMAX_SB_LEN) ? OMAX_SB_LEN : sb_len; - if (copy_to_user(cmd_in, sreq->sr_sense_buffer, sb_len)) + if (copy_to_user(cmd_in, sense, sb_len)) result = -EFAULT; } else { if (copy_to_user(cmd_in, buf, outlen)) result = -EFAULT; } - scsi_release_request(sreq); error: kfree(buf); return result; diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 278e0c99b2ae..3f3accd6cd46 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1615,7 +1615,7 @@ void scsi_exit_queue(void) /** * __scsi_mode_sense - issue a mode sense, falling back from 10 to * six bytes if necessary. - * @sreq: SCSI request to fill in with the MODE_SENSE + * @sdev: SCSI device to be queried * @dbd: set if mode sense will allow block descriptors to be returned * @modepage: mode page being requested * @buffer: request buffer (may not be smaller than eight bytes) @@ -1623,26 +1623,38 @@ void scsi_exit_queue(void) * @timeout: command timeout * @retries: number of retries before failing * @data: returns a structure abstracting the mode header data + * @sense: place to put sense data (or NULL if no sense to be collected). + * must be SCSI_SENSE_BUFFERSIZE big. * * Returns zero if unsuccessful, or the header offset (either 4 * or 8 depending on whether a six or ten byte command was * issued) if successful. **/ int -__scsi_mode_sense(struct scsi_request *sreq, int dbd, int modepage, +scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, unsigned char *buffer, int len, int timeout, int retries, - struct scsi_mode_data *data) { + struct scsi_mode_data *data, char *sense) { unsigned char cmd[12]; int use_10_for_ms; int header_length; + int result; + char *sense_buffer = NULL; memset(data, 0, sizeof(*data)); memset(&cmd[0], 0, 12); cmd[1] = dbd & 0x18; /* allows DBD and LLBA bits */ cmd[2] = modepage; + if (!sense) { + sense_buffer = kmalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL); + if (!sense_buffer) { + dev_printk(KERN_ERR, &sdev->sdev_gendev, "failed to allocate sense buffer\n"); + return 0; + } + sense = sense_buffer; + } retry: - use_10_for_ms = sreq->sr_device->use_10_for_ms; + use_10_for_ms = sdev->use_10_for_ms; if (use_10_for_ms) { if (len < 8) @@ -1660,36 +1672,35 @@ __scsi_mode_sense(struct scsi_request *sreq, int dbd, int modepage, header_length = 4; } - sreq->sr_cmd_len = 0; - memset(sreq->sr_sense_buffer, 0, sizeof(sreq->sr_sense_buffer)); - sreq->sr_data_direction = DMA_FROM_DEVICE; + memset(sense, 0, SCSI_SENSE_BUFFERSIZE); memset(buffer, 0, len); - scsi_wait_req(sreq, cmd, buffer, len, timeout, retries); + result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buffer, len, + sense, timeout, retries); /* This code looks awful: what it's doing is making sure an * ILLEGAL REQUEST sense return identifies the actual command * byte as the problem. MODE_SENSE commands can return * ILLEGAL REQUEST if the code page isn't supported */ - if (use_10_for_ms && !scsi_status_is_good(sreq->sr_result) && - (driver_byte(sreq->sr_result) & DRIVER_SENSE)) { + if (use_10_for_ms && !scsi_status_is_good(result) && + (driver_byte(result) & DRIVER_SENSE)) { struct scsi_sense_hdr sshdr; - if (scsi_request_normalize_sense(sreq, &sshdr)) { + if (scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr)) { if ((sshdr.sense_key == ILLEGAL_REQUEST) && (sshdr.asc == 0x20) && (sshdr.ascq == 0)) { /* * Invalid command operation code */ - sreq->sr_device->use_10_for_ms = 0; + sdev->use_10_for_ms = 0; goto retry; } } } - if(scsi_status_is_good(sreq->sr_result)) { + if(scsi_status_is_good(result)) { data->header_length = header_length; if(use_10_for_ms) { data->length = buffer[0]*256 + buffer[1] + 2; @@ -1706,73 +1717,34 @@ __scsi_mode_sense(struct scsi_request *sreq, int dbd, int modepage, } } - return sreq->sr_result; -} -EXPORT_SYMBOL(__scsi_mode_sense); - -/** - * scsi_mode_sense - issue a mode sense, falling back from 10 to - * six bytes if necessary. - * @sdev: scsi device to send command to. - * @dbd: set if mode sense will disable block descriptors in the return - * @modepage: mode page being requested - * @buffer: request buffer (may not be smaller than eight bytes) - * @len: length of request buffer. - * @timeout: command timeout - * @retries: number of retries before failing - * - * Returns zero if unsuccessful, or the header offset (either 4 - * or 8 depending on whether a six or ten byte command was - * issued) if successful. - **/ -int -scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, - unsigned char *buffer, int len, int timeout, int retries, - struct scsi_mode_data *data) -{ - struct scsi_request *sreq = scsi_allocate_request(sdev, GFP_KERNEL); - int ret; - - if (!sreq) - return -1; - - ret = __scsi_mode_sense(sreq, dbd, modepage, buffer, len, - timeout, retries, data); - - scsi_release_request(sreq); - - return ret; + kfree(sense_buffer); + return result; } EXPORT_SYMBOL(scsi_mode_sense); int scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries) { - struct scsi_request *sreq; char cmd[] = { TEST_UNIT_READY, 0, 0, 0, 0, 0, }; + char sense[SCSI_SENSE_BUFFERSIZE]; int result; - sreq = scsi_allocate_request(sdev, GFP_KERNEL); - if (!sreq) - return -ENOMEM; + result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, sense, + timeout, retries); - sreq->sr_data_direction = DMA_NONE; - scsi_wait_req(sreq, cmd, NULL, 0, timeout, retries); - - if ((driver_byte(sreq->sr_result) & DRIVER_SENSE) && sdev->removable) { + if ((driver_byte(result) & DRIVER_SENSE) && sdev->removable) { struct scsi_sense_hdr sshdr; - if ((scsi_request_normalize_sense(sreq, &sshdr)) && + if ((scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, + &sshdr)) && ((sshdr.sense_key == UNIT_ATTENTION) || (sshdr.sense_key == NOT_READY))) { sdev->changed = 1; - sreq->sr_result = 0; + result = 0; } } - result = sreq->sr_result; - scsi_release_request(sreq); return result; } EXPORT_SYMBOL(scsi_test_unit_ready); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 0410e1bf109a..15c2039059c9 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1299,8 +1299,9 @@ static inline int sd_do_mode_sense(struct scsi_request *SRpnt, int dbd, int modepage, unsigned char *buffer, int len, struct scsi_mode_data *data) { - return __scsi_mode_sense(SRpnt, dbd, modepage, buffer, len, - SD_TIMEOUT, SD_MAX_RETRIES, data); + return scsi_mode_sense(SRpnt->sr_device, dbd, modepage, buffer, len, + SD_TIMEOUT, SD_MAX_RETRIES, data, + SRpnt->sr_sense_buffer); } /* diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 2f259f249522..8cbe6e004187 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -817,7 +817,7 @@ static void get_capabilities(struct scsi_cd *cd) /* ask for mode page 0x2a */ rc = scsi_mode_sense(cd->device, 0, 0x2a, buffer, 128, - SR_TIMEOUT, 3, &data); + SR_TIMEOUT, 3, &data, NULL); if (!scsi_status_is_good(rc)) { /* failed, drive doesn't have capabilities mode page */ diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 835af8ecbb7c..9181068883ce 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -8,9 +8,17 @@ struct request_queue; struct scsi_cmnd; -struct scsi_mode_data; struct scsi_lun; +struct scsi_mode_data { + __u32 length; + __u16 block_descriptor_length; + __u8 medium_type; + __u8 device_specific; + __u8 header_length; + __u8 longlba:1; +}; + /* * sdev state: If you alter this, you also need to alter scsi_sysfs.c * (for the ascii descriptions) and the state model enforcer: @@ -228,7 +236,8 @@ extern int scsi_set_medium_removal(struct scsi_device *, char); extern int scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, unsigned char *buffer, int len, int timeout, - int retries, struct scsi_mode_data *data); + int retries, struct scsi_mode_data *data, + char *sense); extern int scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries); extern int scsi_device_set_state(struct scsi_device *sdev, diff --git a/include/scsi/scsi_request.h b/include/scsi/scsi_request.h index d64903a617c3..f5dfdfec9fea 100644 --- a/include/scsi/scsi_request.h +++ b/include/scsi/scsi_request.h @@ -58,19 +58,4 @@ extern int scsi_execute_req(struct scsi_device *sdev, unsigned char *cmd, int data_direction, void *buffer, unsigned bufflen, unsigned char *sense, int timeout, int retries); -struct scsi_mode_data { - __u32 length; - __u16 block_descriptor_length; - __u8 medium_type; - __u8 device_specific; - __u8 header_length; - __u8 longlba:1; -}; - -extern int __scsi_mode_sense(struct scsi_request *SRpnt, int dbd, - int modepage, unsigned char *buffer, int len, - int timeout, int retries, - struct scsi_mode_data *data); - - #endif /* _SCSI_SCSI_REQUEST_H */ From 33aa687db90dd8541bd5e9a762eebf880eaee767 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sun, 28 Aug 2005 11:31:14 -0500 Subject: [PATCH 074/114] [SCSI] convert SPI transport class to scsi_execute This one's slightly more difficult. The transport class uses REQ_FAILFAST, so another interface (scsi_execute) had to be invented to take the extra flag. Also, the sense functions are shifted around to allow spi_execute to place data directly into a struct scsi_sense_hdr. With this change, there's probably a lot of unnecessary sense buffer allocation going on which we can fix later. Signed-off-by: James Bottomley --- drivers/scsi/scsi_error.c | 6 +- drivers/scsi/scsi_lib.c | 13 ++-- drivers/scsi/scsi_transport_spi.c | 122 ++++++++++++++---------------- include/scsi/scsi_device.h | 13 ++++ include/scsi/scsi_eh.h | 8 ++ include/scsi/scsi_request.h | 4 - 6 files changed, 89 insertions(+), 77 deletions(-) diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index e9c451ba71fc..2686d5672e5e 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -1847,12 +1847,16 @@ EXPORT_SYMBOL(scsi_reset_provider); int scsi_normalize_sense(const u8 *sense_buffer, int sb_len, struct scsi_sense_hdr *sshdr) { - if (!sense_buffer || !sb_len || (sense_buffer[0] & 0x70) != 0x70) + if (!sense_buffer || !sb_len) return 0; memset(sshdr, 0, sizeof(struct scsi_sense_hdr)); sshdr->response_code = (sense_buffer[0] & 0x7f); + + if (!scsi_sense_valid(sshdr)) + return 0; + if (sshdr->response_code >= 0x72) { /* * descriptor format diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 3f3accd6cd46..42edf29223ab 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -282,7 +282,7 @@ void scsi_wait_req(struct scsi_request *sreq, const void *cmnd, void *buffer, EXPORT_SYMBOL(scsi_wait_req); /** - * scsi_execute_req - insert request and wait for the result + * scsi_execute - insert request and wait for the result * @sdev: scsi device * @cmd: scsi command * @data_direction: data direction @@ -291,13 +291,14 @@ EXPORT_SYMBOL(scsi_wait_req); * @sense: optional sense buffer * @timeout: request timeout in seconds * @retries: number of times to retry request + * @flags: or into request flags; * * scsi_execute_req returns the req->errors value which is the * the scsi_cmnd result field. **/ -int scsi_execute_req(struct scsi_device *sdev, unsigned char *cmd, - int data_direction, void *buffer, unsigned bufflen, - unsigned char *sense, int timeout, int retries) +int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd, + int data_direction, void *buffer, unsigned bufflen, + unsigned char *sense, int timeout, int retries, int flags) { struct request *req; int write = (data_direction == DMA_TO_DEVICE); @@ -314,7 +315,7 @@ int scsi_execute_req(struct scsi_device *sdev, unsigned char *cmd, req->sense = sense; req->sense_len = 0; req->timeout = timeout; - req->flags |= REQ_BLOCK_PC | REQ_SPECIAL; + req->flags |= flags | REQ_BLOCK_PC | REQ_SPECIAL; /* * head injection *required* here otherwise quiesce won't work @@ -328,7 +329,7 @@ int scsi_execute_req(struct scsi_device *sdev, unsigned char *cmd, return ret; } -EXPORT_SYMBOL(scsi_execute_req); +EXPORT_SYMBOL(scsi_execute); /* * Function: scsi_init_cmd_errh() diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c index 89f6b7feb9c2..874042f1899d 100644 --- a/drivers/scsi/scsi_transport_spi.c +++ b/drivers/scsi/scsi_transport_spi.c @@ -28,7 +28,7 @@ #include "scsi_priv.h" #include #include -#include +#include #include #include #include @@ -108,25 +108,33 @@ static int sprint_frac(char *dest, int value, int denom) /* Modification of scsi_wait_req that will clear UNIT ATTENTION conditions * resulting from (likely) bus and device resets */ -static void spi_wait_req(struct scsi_request *sreq, const void *cmd, - void *buffer, unsigned bufflen) +static int spi_execute(struct scsi_device *sdev, const void *cmd, + enum dma_data_direction dir, + void *buffer, unsigned bufflen, + struct scsi_sense_hdr *sshdr) { - int i; + int i, result; + unsigned char sense[SCSI_SENSE_BUFFERSIZE]; for(i = 0; i < DV_RETRIES; i++) { - sreq->sr_request->flags |= REQ_FAILFAST; - scsi_wait_req(sreq, cmd, buffer, bufflen, - DV_TIMEOUT, /* retries */ 1); - if (sreq->sr_result & DRIVER_SENSE) { - struct scsi_sense_hdr sshdr; + /* FIXME: need to set REQ_FAILFAST */ + result = scsi_execute(sdev, cmd, dir, buffer, bufflen, + sense, DV_TIMEOUT, /* retries */ 1, + REQ_FAILFAST); + if (result & DRIVER_SENSE) { + struct scsi_sense_hdr sshdr_tmp; + if (!sshdr) + sshdr = &sshdr_tmp; - if (scsi_request_normalize_sense(sreq, &sshdr) - && sshdr.sense_key == UNIT_ATTENTION) + if (scsi_normalize_sense(sense, sizeof(*sense), + sshdr) + && sshdr->sense_key == UNIT_ATTENTION) continue; } break; } + return result; } static struct { @@ -546,13 +554,13 @@ enum spi_compare_returns { /* This is for read/write Domain Validation: If the device supports * an echo buffer, we do read/write tests to it */ static enum spi_compare_returns -spi_dv_device_echo_buffer(struct scsi_request *sreq, u8 *buffer, +spi_dv_device_echo_buffer(struct scsi_device *sdev, u8 *buffer, u8 *ptr, const int retries) { - struct scsi_device *sdev = sreq->sr_device; int len = ptr - buffer; - int j, k, r; + int j, k, r, result; unsigned int pattern = 0x0000ffff; + struct scsi_sense_hdr sshdr; const char spi_write_buffer[] = { WRITE_BUFFER, 0x0a, 0, 0, 0, 0, 0, len >> 8, len & 0xff, 0 @@ -597,14 +605,12 @@ spi_dv_device_echo_buffer(struct scsi_request *sreq, u8 *buffer, } for (r = 0; r < retries; r++) { - sreq->sr_cmd_len = 0; /* wait_req to fill in */ - sreq->sr_data_direction = DMA_TO_DEVICE; - spi_wait_req(sreq, spi_write_buffer, buffer, len); - if(sreq->sr_result || !scsi_device_online(sdev)) { - struct scsi_sense_hdr sshdr; + result = spi_execute(sdev, spi_write_buffer, DMA_TO_DEVICE, + buffer, len, &sshdr); + if(result || !scsi_device_online(sdev)) { scsi_device_set_state(sdev, SDEV_QUIESCE); - if (scsi_request_normalize_sense(sreq, &sshdr) + if (scsi_sense_valid(&sshdr) && sshdr.sense_key == ILLEGAL_REQUEST /* INVALID FIELD IN CDB */ && sshdr.asc == 0x24 && sshdr.ascq == 0x00) @@ -616,14 +622,13 @@ spi_dv_device_echo_buffer(struct scsi_request *sreq, u8 *buffer, return SPI_COMPARE_SKIP_TEST; - SPI_PRINTK(sdev->sdev_target, KERN_ERR, "Write Buffer failure %x\n", sreq->sr_result); + SPI_PRINTK(sdev->sdev_target, KERN_ERR, "Write Buffer failure %x\n", result); return SPI_COMPARE_FAILURE; } memset(ptr, 0, len); - sreq->sr_cmd_len = 0; /* wait_req to fill in */ - sreq->sr_data_direction = DMA_FROM_DEVICE; - spi_wait_req(sreq, spi_read_buffer, ptr, len); + spi_execute(sdev, spi_read_buffer, DMA_FROM_DEVICE, + ptr, len, NULL); scsi_device_set_state(sdev, SDEV_QUIESCE); if (memcmp(buffer, ptr, len) != 0) @@ -635,25 +640,22 @@ spi_dv_device_echo_buffer(struct scsi_request *sreq, u8 *buffer, /* This is for the simplest form of Domain Validation: a read test * on the inquiry data from the device */ static enum spi_compare_returns -spi_dv_device_compare_inquiry(struct scsi_request *sreq, u8 *buffer, +spi_dv_device_compare_inquiry(struct scsi_device *sdev, u8 *buffer, u8 *ptr, const int retries) { - int r; - const int len = sreq->sr_device->inquiry_len; - struct scsi_device *sdev = sreq->sr_device; + int r, result; + const int len = sdev->inquiry_len; const char spi_inquiry[] = { INQUIRY, 0, 0, 0, len, 0 }; for (r = 0; r < retries; r++) { - sreq->sr_cmd_len = 0; /* wait_req to fill in */ - sreq->sr_data_direction = DMA_FROM_DEVICE; - memset(ptr, 0, len); - spi_wait_req(sreq, spi_inquiry, ptr, len); + result = spi_execute(sdev, spi_inquiry, DMA_FROM_DEVICE, + ptr, len, NULL); - if(sreq->sr_result || !scsi_device_online(sdev)) { + if(result || !scsi_device_online(sdev)) { scsi_device_set_state(sdev, SDEV_QUIESCE); return SPI_COMPARE_FAILURE; } @@ -674,12 +676,11 @@ spi_dv_device_compare_inquiry(struct scsi_request *sreq, u8 *buffer, } static enum spi_compare_returns -spi_dv_retrain(struct scsi_request *sreq, u8 *buffer, u8 *ptr, +spi_dv_retrain(struct scsi_device *sdev, u8 *buffer, u8 *ptr, enum spi_compare_returns - (*compare_fn)(struct scsi_request *, u8 *, u8 *, int)) + (*compare_fn)(struct scsi_device *, u8 *, u8 *, int)) { - struct spi_internal *i = to_spi_internal(sreq->sr_host->transportt); - struct scsi_device *sdev = sreq->sr_device; + struct spi_internal *i = to_spi_internal(sdev->host->transportt); struct scsi_target *starget = sdev->sdev_target; int period = 0, prevperiod = 0; enum spi_compare_returns retval; @@ -687,7 +688,7 @@ spi_dv_retrain(struct scsi_request *sreq, u8 *buffer, u8 *ptr, for (;;) { int newperiod; - retval = compare_fn(sreq, buffer, ptr, DV_LOOPS); + retval = compare_fn(sdev, buffer, ptr, DV_LOOPS); if (retval == SPI_COMPARE_SUCCESS || retval == SPI_COMPARE_SKIP_TEST) @@ -733,9 +734,9 @@ spi_dv_retrain(struct scsi_request *sreq, u8 *buffer, u8 *ptr, } static int -spi_dv_device_get_echo_buffer(struct scsi_request *sreq, u8 *buffer) +spi_dv_device_get_echo_buffer(struct scsi_device *sdev, u8 *buffer) { - int l; + int l, result; /* first off do a test unit ready. This can error out * because of reservations or some other reason. If it @@ -751,18 +752,16 @@ spi_dv_device_get_echo_buffer(struct scsi_request *sreq, u8 *buffer) }; - sreq->sr_cmd_len = 0; - sreq->sr_data_direction = DMA_NONE; - /* We send a set of three TURs to clear any outstanding * unit attention conditions if they exist (Otherwise the * buffer tests won't be happy). If the TUR still fails * (reservation conflict, device not ready, etc) just * skip the write tests */ for (l = 0; ; l++) { - spi_wait_req(sreq, spi_test_unit_ready, NULL, 0); + result = spi_execute(sdev, spi_test_unit_ready, DMA_NONE, + NULL, 0, NULL); - if(sreq->sr_result) { + if(result) { if(l >= 3) return 0; } else { @@ -771,12 +770,10 @@ spi_dv_device_get_echo_buffer(struct scsi_request *sreq, u8 *buffer) } } - sreq->sr_cmd_len = 0; - sreq->sr_data_direction = DMA_FROM_DEVICE; + result = spi_execute(sdev, spi_read_buffer_descriptor, + DMA_FROM_DEVICE, buffer, 4, NULL); - spi_wait_req(sreq, spi_read_buffer_descriptor, buffer, 4); - - if (sreq->sr_result) + if (result) /* Device has no echo buffer */ return 0; @@ -784,17 +781,16 @@ spi_dv_device_get_echo_buffer(struct scsi_request *sreq, u8 *buffer) } static void -spi_dv_device_internal(struct scsi_request *sreq, u8 *buffer) +spi_dv_device_internal(struct scsi_device *sdev, u8 *buffer) { - struct spi_internal *i = to_spi_internal(sreq->sr_host->transportt); - struct scsi_device *sdev = sreq->sr_device; + struct spi_internal *i = to_spi_internal(sdev->host->transportt); struct scsi_target *starget = sdev->sdev_target; int len = sdev->inquiry_len; /* first set us up for narrow async */ DV_SET(offset, 0); DV_SET(width, 0); - if (spi_dv_device_compare_inquiry(sreq, buffer, buffer, DV_LOOPS) + if (spi_dv_device_compare_inquiry(sdev, buffer, buffer, DV_LOOPS) != SPI_COMPARE_SUCCESS) { SPI_PRINTK(starget, KERN_ERR, "Domain Validation Initial Inquiry Failed\n"); /* FIXME: should probably offline the device here? */ @@ -806,7 +802,7 @@ spi_dv_device_internal(struct scsi_request *sreq, u8 *buffer) scsi_device_wide(sdev)) { i->f->set_width(starget, 1); - if (spi_dv_device_compare_inquiry(sreq, buffer, + if (spi_dv_device_compare_inquiry(sdev, buffer, buffer + len, DV_LOOPS) != SPI_COMPARE_SUCCESS) { @@ -827,7 +823,7 @@ spi_dv_device_internal(struct scsi_request *sreq, u8 *buffer) len = 0; if (scsi_device_dt(sdev)) - len = spi_dv_device_get_echo_buffer(sreq, buffer); + len = spi_dv_device_get_echo_buffer(sdev, buffer); retry: @@ -853,7 +849,7 @@ spi_dv_device_internal(struct scsi_request *sreq, u8 *buffer) if (len == 0) { SPI_PRINTK(starget, KERN_INFO, "Domain Validation skipping write tests\n"); - spi_dv_retrain(sreq, buffer, buffer + len, + spi_dv_retrain(sdev, buffer, buffer + len, spi_dv_device_compare_inquiry); return; } @@ -863,7 +859,7 @@ spi_dv_device_internal(struct scsi_request *sreq, u8 *buffer) len = SPI_MAX_ECHO_BUFFER_SIZE; } - if (spi_dv_retrain(sreq, buffer, buffer + len, + if (spi_dv_retrain(sdev, buffer, buffer + len, spi_dv_device_echo_buffer) == SPI_COMPARE_SKIP_TEST) { /* OK, the stupid drive can't do a write echo buffer @@ -886,16 +882,12 @@ spi_dv_device_internal(struct scsi_request *sreq, u8 *buffer) void spi_dv_device(struct scsi_device *sdev) { - struct scsi_request *sreq = scsi_allocate_request(sdev, GFP_KERNEL); struct scsi_target *starget = sdev->sdev_target; u8 *buffer; const int len = SPI_MAX_ECHO_BUFFER_SIZE*2; - if (unlikely(!sreq)) - return; - if (unlikely(scsi_device_get(sdev))) - goto out_free_req; + return; buffer = kmalloc(len, GFP_KERNEL); @@ -916,7 +908,7 @@ spi_dv_device(struct scsi_device *sdev) SPI_PRINTK(starget, KERN_INFO, "Beginning Domain Validation\n"); - spi_dv_device_internal(sreq, buffer); + spi_dv_device_internal(sdev, buffer); SPI_PRINTK(starget, KERN_INFO, "Ending Domain Validation\n"); @@ -931,8 +923,6 @@ spi_dv_device(struct scsi_device *sdev) kfree(buffer); out_put: scsi_device_put(sdev); - out_free_req: - scsi_release_request(sreq); } EXPORT_SYMBOL(spi_dv_device); diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 9181068883ce..5ad08b70763c 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -256,6 +256,19 @@ extern void int_to_scsilun(unsigned int, struct scsi_lun *); extern const char *scsi_device_state_name(enum scsi_device_state); extern int scsi_is_sdev_device(const struct device *); extern int scsi_is_target_device(const struct device *); +extern int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd, + int data_direction, void *buffer, unsigned bufflen, + unsigned char *sense, int timeout, int retries, + int flag); + +static inline int +scsi_execute_req(struct scsi_device *sdev, const unsigned char *cmd, + int data_direction, void *buffer, unsigned bufflen, + unsigned char *sense, int timeout, int retries) +{ + return scsi_execute(sdev, cmd, data_direction, buffer, bufflen, sense, + timeout, retries, 0); +} static inline int scsi_device_online(struct scsi_device *sdev) { return sdev->sdev_state != SDEV_OFFLINE; diff --git a/include/scsi/scsi_eh.h b/include/scsi/scsi_eh.h index 80557f879e3e..b24d224281bd 100644 --- a/include/scsi/scsi_eh.h +++ b/include/scsi/scsi_eh.h @@ -26,6 +26,14 @@ struct scsi_sense_hdr { /* See SPC-3 section 4.5 */ u8 additional_length; /* always 0 for fixed sense format */ }; +static inline int scsi_sense_valid(struct scsi_sense_hdr *sshdr) +{ + if (!sshdr) + return 0; + + return (sshdr->response_code & 0x70) == 0x70; +} + extern void scsi_add_timer(struct scsi_cmnd *, int, void (*)(struct scsi_cmnd *)); diff --git a/include/scsi/scsi_request.h b/include/scsi/scsi_request.h index f5dfdfec9fea..6a140020d7cb 100644 --- a/include/scsi/scsi_request.h +++ b/include/scsi/scsi_request.h @@ -54,8 +54,4 @@ extern void scsi_do_req(struct scsi_request *, const void *cmnd, void *buffer, unsigned bufflen, void (*done) (struct scsi_cmnd *), int timeout, int retries); -extern int scsi_execute_req(struct scsi_device *sdev, unsigned char *cmd, - int data_direction, void *buffer, unsigned bufflen, - unsigned char *sense, int timeout, int retries); - #endif /* _SCSI_SCSI_REQUEST_H */ From ea73a9f23906c374b697cd5b0d64f6dceced63de Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sun, 28 Aug 2005 11:33:52 -0500 Subject: [PATCH 075/114] [SCSI] convert sd to scsi_execute_req (and update the scsi_execute_req API) This one removes struct scsi_request entirely from sd. In the process, I noticed we have no callers of scsi_wait_req who don't immediately normalise the sense, so I updated the API to make it take a struct scsi_sense_hdr instead of simply a big sense buffer. Signed-off-by: James Bottomley --- drivers/scsi/constants.c | 48 ++++++----- drivers/scsi/scsi_ioctl.c | 15 ++-- drivers/scsi/scsi_lib.c | 67 +++++++++------- drivers/scsi/scsi_scan.c | 13 +-- drivers/scsi/sd.c | 160 +++++++++++++++---------------------- include/scsi/scsi_dbg.h | 2 + include/scsi/scsi_device.h | 14 ++-- 7 files changed, 146 insertions(+), 173 deletions(-) diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c index 0d58d3538bdf..f6be2c1c3942 100644 --- a/drivers/scsi/constants.c +++ b/drivers/scsi/constants.c @@ -1156,6 +1156,31 @@ scsi_show_extd_sense(unsigned char asc, unsigned char ascq) } } +void +scsi_print_sense_hdr(const char *name, struct scsi_sense_hdr *sshdr) +{ + const char *sense_txt; + /* An example of deferred is when an earlier write to disk cache + * succeeded, but now the disk discovers that it cannot write the + * data to the magnetic media. + */ + const char *error = scsi_sense_is_deferred(sshdr) ? + "<>" : "Current"; + printk(KERN_INFO "%s: %s", name, error); + if (sshdr->response_code >= 0x72) + printk(" [descriptor]"); + + sense_txt = scsi_sense_key_string(sshdr->sense_key); + if (sense_txt) + printk(": sense key: %s\n", sense_txt); + else + printk(": sense key=0x%x\n", sshdr->sense_key); + printk(KERN_INFO " "); + scsi_show_extd_sense(sshdr->asc, sshdr->ascq); + printk("\n"); +} +EXPORT_SYMBOL(scsi_print_sense_hdr); + /* Print sense information */ void __scsi_print_sense(const char *name, const unsigned char *sense_buffer, @@ -1163,8 +1188,6 @@ __scsi_print_sense(const char *name, const unsigned char *sense_buffer, { int k, num, res; unsigned int info; - const char *error; - const char *sense_txt; struct scsi_sense_hdr ssh; res = scsi_normalize_sense(sense_buffer, sense_len, &ssh); @@ -1182,26 +1205,7 @@ __scsi_print_sense(const char *name, const unsigned char *sense_buffer, printk("\n"); return; } - - /* An example of deferred is when an earlier write to disk cache - * succeeded, but now the disk discovers that it cannot write the - * data to the magnetic media. - */ - error = scsi_sense_is_deferred(&ssh) ? - "<>" : "Current"; - printk(KERN_INFO "%s: %s", name, error); - if (ssh.response_code >= 0x72) - printk(" [descriptor]"); - - sense_txt = scsi_sense_key_string(ssh.sense_key); - if (sense_txt) - printk(": sense key: %s\n", sense_txt); - else - printk(": sense key=0x%x\n", ssh.sense_key); - printk(KERN_INFO " "); - scsi_show_extd_sense(ssh.asc, ssh.ascq); - printk("\n"); - + scsi_print_sense_hdr(name, &ssh); if (ssh.response_code < 0x72) { /* only decode extras for "fixed" format now */ char buff[80]; diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index 5f399c9c68ee..179a767d221d 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c @@ -90,19 +90,16 @@ static int ioctl_internal_command(struct scsi_device *sdev, char *cmd, { int result; struct scsi_sense_hdr sshdr; - char sense[SCSI_SENSE_BUFFERSIZE]; SCSI_LOG_IOCTL(1, printk("Trying ioctl with scsi command %d\n", *cmd)); - - memset(sense, 0, sizeof(*sense)); result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, - sense, timeout, retries); + &sshdr, timeout, retries); SCSI_LOG_IOCTL(2, printk("Ioctl returned 0x%x\n", result)); if ((driver_byte(result) & DRIVER_SENSE) && - (scsi_normalize_sense(sense, sizeof(*sense), &sshdr))) { + (scsi_sense_valid(&sshdr))) { switch (sshdr.sense_key) { case ILLEGAL_REQUEST: if (cmd[0] == ALLOW_MEDIUM_REMOVAL) @@ -132,7 +129,7 @@ static int ioctl_internal_command(struct scsi_device *sdev, char *cmd, sdev->id, sdev->lun, result); - __scsi_print_sense(" ", sense, sizeof(*sense)); + scsi_print_sense_hdr(" ", &sshdr); break; } } @@ -315,9 +312,9 @@ int scsi_ioctl_send_command(struct scsi_device *sdev, break; } - result = scsi_execute_req(sdev, cmd, data_direction, buf, needed, - sense, timeout, retries); - + result = scsi_execute(sdev, cmd, data_direction, buf, needed, + sense, timeout, retries, 0); + /* * If there was an error condition, pass the info back to the user. */ diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 42edf29223ab..bdea26b56dc4 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -293,8 +293,8 @@ EXPORT_SYMBOL(scsi_wait_req); * @retries: number of times to retry request * @flags: or into request flags; * - * scsi_execute_req returns the req->errors value which is the - * the scsi_cmnd result field. + * returns the req->errors value which is the the scsi_cmnd result + * field. **/ int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd, int data_direction, void *buffer, unsigned bufflen, @@ -328,9 +328,31 @@ int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd, return ret; } - EXPORT_SYMBOL(scsi_execute); + +int scsi_execute_req(struct scsi_device *sdev, const unsigned char *cmd, + int data_direction, void *buffer, unsigned bufflen, + struct scsi_sense_hdr *sshdr, int timeout, int retries) +{ + char *sense = NULL; + + if (sshdr) { + sense = kmalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL); + if (!sense) + return DRIVER_ERROR << 24; + memset(sense, 0, sizeof(*sense)); + } + int result = scsi_execute(sdev, cmd, data_direction, buffer, bufflen, + sense, timeout, retries, 0); + if (sshdr) + scsi_normalize_sense(sense, sizeof(*sense), sshdr); + + kfree(sense); + return result; +} +EXPORT_SYMBOL(scsi_execute_req); + /* * Function: scsi_init_cmd_errh() * @@ -1614,7 +1636,7 @@ void scsi_exit_queue(void) } } /** - * __scsi_mode_sense - issue a mode sense, falling back from 10 to + * scsi_mode_sense - issue a mode sense, falling back from 10 to * six bytes if necessary. * @sdev: SCSI device to be queried * @dbd: set if mode sense will allow block descriptors to be returned @@ -1634,26 +1656,22 @@ void scsi_exit_queue(void) int scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, unsigned char *buffer, int len, int timeout, int retries, - struct scsi_mode_data *data, char *sense) { + struct scsi_mode_data *data, struct scsi_sense_hdr *sshdr) { unsigned char cmd[12]; int use_10_for_ms; int header_length; int result; - char *sense_buffer = NULL; + struct scsi_sense_hdr my_sshdr; memset(data, 0, sizeof(*data)); memset(&cmd[0], 0, 12); cmd[1] = dbd & 0x18; /* allows DBD and LLBA bits */ cmd[2] = modepage; - if (!sense) { - sense_buffer = kmalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL); - if (!sense_buffer) { - dev_printk(KERN_ERR, &sdev->sdev_gendev, "failed to allocate sense buffer\n"); - return 0; - } - sense = sense_buffer; - } + /* caller might not be interested in sense, but we need it */ + if (!sshdr) + sshdr = &my_sshdr; + retry: use_10_for_ms = sdev->use_10_for_ms; @@ -1673,12 +1691,10 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, header_length = 4; } - memset(sense, 0, SCSI_SENSE_BUFFERSIZE); - memset(buffer, 0, len); result = scsi_execute_req(sdev, cmd, DMA_FROM_DEVICE, buffer, len, - sense, timeout, retries); + sshdr, timeout, retries); /* This code looks awful: what it's doing is making sure an * ILLEGAL REQUEST sense return identifies the actual command @@ -1687,11 +1703,9 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, if (use_10_for_ms && !scsi_status_is_good(result) && (driver_byte(result) & DRIVER_SENSE)) { - struct scsi_sense_hdr sshdr; - - if (scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, &sshdr)) { - if ((sshdr.sense_key == ILLEGAL_REQUEST) && - (sshdr.asc == 0x20) && (sshdr.ascq == 0)) { + if (scsi_sense_valid(sshdr)) { + if ((sshdr->sense_key == ILLEGAL_REQUEST) && + (sshdr->asc == 0x20) && (sshdr->ascq == 0)) { /* * Invalid command operation code */ @@ -1718,7 +1732,6 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, } } - kfree(sense_buffer); return result; } EXPORT_SYMBOL(scsi_mode_sense); @@ -1729,17 +1742,15 @@ scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries) char cmd[] = { TEST_UNIT_READY, 0, 0, 0, 0, 0, }; - char sense[SCSI_SENSE_BUFFERSIZE]; + struct scsi_sense_hdr sshdr; int result; - result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, sense, + result = scsi_execute_req(sdev, cmd, DMA_NONE, NULL, 0, &sshdr, timeout, retries); if ((driver_byte(result) & DRIVER_SENSE) && sdev->removable) { - struct scsi_sense_hdr sshdr; - if ((scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, - &sshdr)) && + if ((scsi_sense_valid(&sshdr)) && ((sshdr.sense_key == UNIT_ATTENTION) || (sshdr.sense_key == NOT_READY))) { sdev->changed = 1; diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 0048beaffc9f..19c9a232a754 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -446,7 +446,6 @@ void scsi_target_reap(struct scsi_target *starget) static int scsi_probe_lun(struct scsi_device *sdev, char *inq_result, int result_len, int *bflags) { - char sense[SCSI_SENSE_BUFFERSIZE]; unsigned char scsi_cmd[MAX_COMMAND_SIZE]; int first_inquiry_len, try_inquiry_len, next_inquiry_len; int response_len = 0; @@ -474,11 +473,10 @@ static int scsi_probe_lun(struct scsi_device *sdev, char *inq_result, scsi_cmd[0] = INQUIRY; scsi_cmd[4] = (unsigned char) try_inquiry_len; - memset(sense, 0, sizeof(sense)); memset(inq_result, 0, try_inquiry_len); result = scsi_execute_req(sdev, scsi_cmd, DMA_FROM_DEVICE, - inq_result, try_inquiry_len, sense, + inq_result, try_inquiry_len, &sshdr, HZ / 2 + HZ * scsi_inq_timeout, 3); SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO "scsi scan: INQUIRY %s " @@ -493,8 +491,7 @@ static int scsi_probe_lun(struct scsi_device *sdev, char *inq_result, * but many buggy devices do so anyway. */ if ((driver_byte(result) & DRIVER_SENSE) && - scsi_normalize_sense(sense, sizeof(sense), - &sshdr)) { + scsi_sense_valid(&sshdr)) { if ((sshdr.sense_key == UNIT_ATTENTION) && ((sshdr.asc == 0x28) || (sshdr.asc == 0x29)) && @@ -1057,7 +1054,6 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags, int rescan) { char devname[64]; - char sense[SCSI_SENSE_BUFFERSIZE]; unsigned char scsi_cmd[MAX_COMMAND_SIZE]; unsigned int length; unsigned int lun; @@ -1134,9 +1130,8 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags, " REPORT LUNS to %s (try %d)\n", devname, retries)); - memset(sense, 0, sizeof(sense)); result = scsi_execute_req(sdev, scsi_cmd, DMA_FROM_DEVICE, - lun_data, length, sense, + lun_data, length, &sshdr, SCSI_TIMEOUT + 4 * HZ, 3); SCSI_LOG_SCAN_BUS(3, printk (KERN_INFO "scsi scan: REPORT LUNS" @@ -1144,7 +1139,7 @@ static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags, ? "failed" : "successful", retries, result)); if (result == 0) break; - else if (scsi_normalize_sense(sense, sizeof(sense), &sshdr)) { + else if (scsi_sense_valid(&sshdr)) { if (sshdr.sense_key != UNIT_ATTENTION) break; } diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 15c2039059c9..611ccde84778 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -59,7 +59,6 @@ #include #include #include -#include #include #include "scsi_logging.h" @@ -125,7 +124,7 @@ static int sd_issue_flush(struct device *, sector_t *); static void sd_end_flush(request_queue_t *, struct request *); static int sd_prepare_flush(request_queue_t *, struct request *); static void sd_read_capacity(struct scsi_disk *sdkp, char *diskname, - struct scsi_request *SRpnt, unsigned char *buffer); + unsigned char *buffer); static struct scsi_driver sd_template = { .owner = THIS_MODULE, @@ -682,19 +681,13 @@ static int sd_media_changed(struct gendisk *disk) static int sd_sync_cache(struct scsi_device *sdp) { - struct scsi_request *sreq; int retries, res; + struct scsi_sense_hdr sshdr; if (!scsi_device_online(sdp)) return -ENODEV; - sreq = scsi_allocate_request(sdp, GFP_KERNEL); - if (!sreq) { - printk("FAILED\n No memory for request\n"); - return -ENOMEM; - } - sreq->sr_data_direction = DMA_NONE; for (retries = 3; retries > 0; --retries) { unsigned char cmd[10] = { 0 }; @@ -703,22 +696,20 @@ static int sd_sync_cache(struct scsi_device *sdp) * Leave the rest of the command zero to indicate * flush everything. */ - scsi_wait_req(sreq, cmd, NULL, 0, SD_TIMEOUT, SD_MAX_RETRIES); - if (sreq->sr_result == 0) + res = scsi_execute_req(sdp, cmd, DMA_NONE, NULL, 0, &sshdr, + SD_TIMEOUT, SD_MAX_RETRIES); + if (res == 0) break; } - res = sreq->sr_result; - if (res) { - printk(KERN_WARNING "FAILED\n status = %x, message = %02x, " + if (res) { printk(KERN_WARNING "FAILED\n status = %x, message = %02x, " "host = %d, driver = %02x\n ", status_byte(res), msg_byte(res), host_byte(res), driver_byte(res)); if (driver_byte(res) & DRIVER_SENSE) - scsi_print_req_sense("sd", sreq); + scsi_print_sense_hdr("sd", &sshdr); } - scsi_release_request(sreq); return res; } @@ -957,22 +948,19 @@ static void sd_rw_intr(struct scsi_cmnd * SCpnt) scsi_io_completion(SCpnt, good_bytes, block_sectors << 9); } -static int media_not_present(struct scsi_disk *sdkp, struct scsi_request *srp) +static int media_not_present(struct scsi_disk *sdkp, + struct scsi_sense_hdr *sshdr) { - struct scsi_sense_hdr sshdr; - if (!srp->sr_result) - return 0; - if (!(driver_byte(srp->sr_result) & DRIVER_SENSE)) + if (!scsi_sense_valid(sshdr)) return 0; /* not invoked for commands that could return deferred errors */ - if (scsi_request_normalize_sense(srp, &sshdr)) { - if (sshdr.sense_key != NOT_READY && - sshdr.sense_key != UNIT_ATTENTION) - return 0; - if (sshdr.asc != 0x3A) /* medium not present */ - return 0; - } + if (sshdr->sense_key != NOT_READY && + sshdr->sense_key != UNIT_ATTENTION) + return 0; + if (sshdr->asc != 0x3A) /* medium not present */ + return 0; + set_media_not_present(sdkp); return 1; } @@ -981,8 +969,8 @@ static int media_not_present(struct scsi_disk *sdkp, struct scsi_request *srp) * spinup disk - called only in sd_revalidate_disk() */ static void -sd_spinup_disk(struct scsi_disk *sdkp, char *diskname, - struct scsi_request *SRpnt, unsigned char *buffer) { +sd_spinup_disk(struct scsi_disk *sdkp, char *diskname) +{ unsigned char cmd[10]; unsigned long spintime_value = 0; int retries, spintime; @@ -1001,18 +989,13 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname, cmd[0] = TEST_UNIT_READY; memset((void *) &cmd[1], 0, 9); - SRpnt->sr_cmd_len = 0; - memset(SRpnt->sr_sense_buffer, 0, - SCSI_SENSE_BUFFERSIZE); - SRpnt->sr_data_direction = DMA_NONE; + the_result = scsi_execute_req(sdkp->device, cmd, + DMA_NONE, NULL, 0, + &sshdr, SD_TIMEOUT, + SD_MAX_RETRIES); - scsi_wait_req (SRpnt, (void *) cmd, (void *) buffer, - 0/*512*/, SD_TIMEOUT, SD_MAX_RETRIES); - - the_result = SRpnt->sr_result; if (the_result) - sense_valid = scsi_request_normalize_sense( - SRpnt, &sshdr); + sense_valid = scsi_sense_valid(&sshdr); retries++; } while (retries < 3 && (!scsi_status_is_good(the_result) || @@ -1024,7 +1007,7 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname, * any media in it, don't bother with any of the rest of * this crap. */ - if (media_not_present(sdkp, SRpnt)) + if (media_not_present(sdkp, &sshdr)) return; if ((driver_byte(the_result) & DRIVER_SENSE) == 0) { @@ -1063,14 +1046,9 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname, cmd[1] = 1; /* Return immediately */ memset((void *) &cmd[2], 0, 8); cmd[4] = 1; /* Start spin cycle */ - SRpnt->sr_cmd_len = 0; - memset(SRpnt->sr_sense_buffer, 0, - SCSI_SENSE_BUFFERSIZE); - - SRpnt->sr_data_direction = DMA_NONE; - scsi_wait_req(SRpnt, (void *)cmd, - (void *) buffer, 0/*512*/, - SD_TIMEOUT, SD_MAX_RETRIES); + scsi_execute_req(sdkp->device, cmd, DMA_NONE, + NULL, 0, &sshdr, + SD_TIMEOUT, SD_MAX_RETRIES); spintime_value = jiffies; } spintime = 1; @@ -1083,7 +1061,7 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname, if(!spintime) { printk(KERN_NOTICE "%s: Unit Not Ready, " "sense:\n", diskname); - scsi_print_req_sense("", SRpnt); + scsi_print_sense_hdr("", &sshdr); } break; } @@ -1104,14 +1082,15 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname, */ static void sd_read_capacity(struct scsi_disk *sdkp, char *diskname, - struct scsi_request *SRpnt, unsigned char *buffer) { + unsigned char *buffer) +{ unsigned char cmd[16]; - struct scsi_device *sdp = sdkp->device; int the_result, retries; int sector_size = 0; int longrc = 0; struct scsi_sense_hdr sshdr; int sense_valid = 0; + struct scsi_device *sdp = sdkp->device; repeat: retries = 3; @@ -1128,20 +1107,15 @@ sd_read_capacity(struct scsi_disk *sdkp, char *diskname, memset((void *) buffer, 0, 8); } - SRpnt->sr_cmd_len = 0; - memset(SRpnt->sr_sense_buffer, 0, SCSI_SENSE_BUFFERSIZE); - SRpnt->sr_data_direction = DMA_FROM_DEVICE; + the_result = scsi_execute_req(sdp, cmd, DMA_FROM_DEVICE, + buffer, longrc ? 12 : 8, &sshdr, + SD_TIMEOUT, SD_MAX_RETRIES); - scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer, - longrc ? 12 : 8, SD_TIMEOUT, SD_MAX_RETRIES); - - if (media_not_present(sdkp, SRpnt)) + if (media_not_present(sdkp, &sshdr)) return; - the_result = SRpnt->sr_result; if (the_result) - sense_valid = scsi_request_normalize_sense(SRpnt, - &sshdr); + sense_valid = scsi_sense_valid(&sshdr); retries--; } while (the_result && retries); @@ -1156,7 +1130,7 @@ sd_read_capacity(struct scsi_disk *sdkp, char *diskname, driver_byte(the_result)); if (driver_byte(the_result) & DRIVER_SENSE) - scsi_print_req_sense("sd", SRpnt); + scsi_print_sense_hdr("sd", &sshdr); else printk("%s : sense not available. \n", diskname); @@ -1296,12 +1270,13 @@ sd_read_capacity(struct scsi_disk *sdkp, char *diskname, /* called with buffer of length 512 */ static inline int -sd_do_mode_sense(struct scsi_request *SRpnt, int dbd, int modepage, - unsigned char *buffer, int len, struct scsi_mode_data *data) +sd_do_mode_sense(struct scsi_device *sdp, int dbd, int modepage, + unsigned char *buffer, int len, struct scsi_mode_data *data, + struct scsi_sense_hdr *sshdr) { - return scsi_mode_sense(SRpnt->sr_device, dbd, modepage, buffer, len, + return scsi_mode_sense(sdp, dbd, modepage, buffer, len, SD_TIMEOUT, SD_MAX_RETRIES, data, - SRpnt->sr_sense_buffer); + sshdr); } /* @@ -1310,25 +1285,27 @@ sd_do_mode_sense(struct scsi_request *SRpnt, int dbd, int modepage, */ static void sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname, - struct scsi_request *SRpnt, unsigned char *buffer) { + unsigned char *buffer) +{ int res; + struct scsi_device *sdp = sdkp->device; struct scsi_mode_data data; set_disk_ro(sdkp->disk, 0); - if (sdkp->device->skip_ms_page_3f) { + if (sdp->skip_ms_page_3f) { printk(KERN_NOTICE "%s: assuming Write Enabled\n", diskname); return; } - if (sdkp->device->use_192_bytes_for_3f) { - res = sd_do_mode_sense(SRpnt, 0, 0x3F, buffer, 192, &data); + if (sdp->use_192_bytes_for_3f) { + res = sd_do_mode_sense(sdp, 0, 0x3F, buffer, 192, &data, NULL); } else { /* * First attempt: ask for all pages (0x3F), but only 4 bytes. * We have to start carefully: some devices hang if we ask * for more than is available. */ - res = sd_do_mode_sense(SRpnt, 0, 0x3F, buffer, 4, &data); + res = sd_do_mode_sense(sdp, 0, 0x3F, buffer, 4, &data, NULL); /* * Second attempt: ask for page 0 When only page 0 is @@ -1337,14 +1314,14 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname, * CDB. */ if (!scsi_status_is_good(res)) - res = sd_do_mode_sense(SRpnt, 0, 0, buffer, 4, &data); + res = sd_do_mode_sense(sdp, 0, 0, buffer, 4, &data, NULL); /* * Third attempt: ask 255 bytes, as we did earlier. */ if (!scsi_status_is_good(res)) - res = sd_do_mode_sense(SRpnt, 0, 0x3F, buffer, 255, - &data); + res = sd_do_mode_sense(sdp, 0, 0x3F, buffer, 255, + &data, NULL); } if (!scsi_status_is_good(res)) { @@ -1366,19 +1343,20 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname, */ static void sd_read_cache_type(struct scsi_disk *sdkp, char *diskname, - struct scsi_request *SRpnt, unsigned char *buffer) + unsigned char *buffer) { int len = 0, res; + struct scsi_device *sdp = sdkp->device; int dbd; int modepage; struct scsi_mode_data data; struct scsi_sense_hdr sshdr; - if (sdkp->device->skip_ms_page_8) + if (sdp->skip_ms_page_8) goto defaults; - if (sdkp->device->type == TYPE_RBC) { + if (sdp->type == TYPE_RBC) { modepage = 6; dbd = 8; } else { @@ -1387,7 +1365,7 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname, } /* cautiously ask */ - res = sd_do_mode_sense(SRpnt, dbd, modepage, buffer, 4, &data); + res = sd_do_mode_sense(sdp, dbd, modepage, buffer, 4, &data, &sshdr); if (!scsi_status_is_good(res)) goto bad_sense; @@ -1408,7 +1386,7 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname, len += data.header_length + data.block_descriptor_length; /* Get the data */ - res = sd_do_mode_sense(SRpnt, dbd, modepage, buffer, len, &data); + res = sd_do_mode_sense(sdp, dbd, modepage, buffer, len, &data, &sshdr); if (scsi_status_is_good(res)) { const char *types[] = { @@ -1440,7 +1418,7 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname, } bad_sense: - if (scsi_request_normalize_sense(SRpnt, &sshdr) && + if (scsi_sense_valid(&sshdr) && sshdr.sense_key == ILLEGAL_REQUEST && sshdr.asc == 0x24 && sshdr.ascq == 0x0) printk(KERN_NOTICE "%s: cache data unavailable\n", @@ -1465,7 +1443,6 @@ static int sd_revalidate_disk(struct gendisk *disk) { struct scsi_disk *sdkp = scsi_disk(disk); struct scsi_device *sdp = sdkp->device; - struct scsi_request *sreq; unsigned char *buffer; SCSI_LOG_HLQUEUE(3, printk("sd_revalidate_disk: disk=%s\n", disk->disk_name)); @@ -1477,18 +1454,11 @@ static int sd_revalidate_disk(struct gendisk *disk) if (!scsi_device_online(sdp)) goto out; - sreq = scsi_allocate_request(sdp, GFP_KERNEL); - if (!sreq) { - printk(KERN_WARNING "(sd_revalidate_disk:) Request allocation " - "failure.\n"); - goto out; - } - buffer = kmalloc(512, GFP_KERNEL | __GFP_DMA); if (!buffer) { printk(KERN_WARNING "(sd_revalidate_disk:) Memory allocation " "failure.\n"); - goto out_release_request; + goto out; } /* defaults, until the device tells us otherwise */ @@ -1499,25 +1469,23 @@ static int sd_revalidate_disk(struct gendisk *disk) sdkp->WCE = 0; sdkp->RCD = 0; - sd_spinup_disk(sdkp, disk->disk_name, sreq, buffer); + sd_spinup_disk(sdkp, disk->disk_name); /* * Without media there is no reason to ask; moreover, some devices * react badly if we do. */ if (sdkp->media_present) { - sd_read_capacity(sdkp, disk->disk_name, sreq, buffer); + sd_read_capacity(sdkp, disk->disk_name, buffer); if (sdp->removable) sd_read_write_protect_flag(sdkp, disk->disk_name, - sreq, buffer); - sd_read_cache_type(sdkp, disk->disk_name, sreq, buffer); + buffer); + sd_read_cache_type(sdkp, disk->disk_name, buffer); } set_capacity(disk, sdkp->capacity); kfree(buffer); - out_release_request: - scsi_release_request(sreq); out: return 0; } diff --git a/include/scsi/scsi_dbg.h b/include/scsi/scsi_dbg.h index 12e90934a7a8..b090a11d7e1c 100644 --- a/include/scsi/scsi_dbg.h +++ b/include/scsi/scsi_dbg.h @@ -3,8 +3,10 @@ struct scsi_cmnd; struct scsi_request; +struct scsi_sense_hdr; extern void scsi_print_command(struct scsi_cmnd *); +extern void scsi_print_sense_hdr(const char *, struct scsi_sense_hdr *); extern void __scsi_print_command(unsigned char *); extern void scsi_print_sense(const char *, struct scsi_cmnd *); extern void scsi_print_req_sense(const char *, struct scsi_request *); diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 5ad08b70763c..da63722c0123 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -9,6 +9,7 @@ struct request_queue; struct scsi_cmnd; struct scsi_lun; +struct scsi_sense_hdr; struct scsi_mode_data { __u32 length; @@ -237,7 +238,7 @@ extern int scsi_set_medium_removal(struct scsi_device *, char); extern int scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, unsigned char *buffer, int len, int timeout, int retries, struct scsi_mode_data *data, - char *sense); + struct scsi_sense_hdr *); extern int scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries); extern int scsi_device_set_state(struct scsi_device *sdev, @@ -260,15 +261,10 @@ extern int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd, int data_direction, void *buffer, unsigned bufflen, unsigned char *sense, int timeout, int retries, int flag); +extern int scsi_execute_req(struct scsi_device *sdev, const unsigned char *cmd, + int data_direction, void *buffer, unsigned bufflen, + struct scsi_sense_hdr *, int timeout, int retries); -static inline int -scsi_execute_req(struct scsi_device *sdev, const unsigned char *cmd, - int data_direction, void *buffer, unsigned bufflen, - unsigned char *sense, int timeout, int retries) -{ - return scsi_execute(sdev, cmd, data_direction, buffer, bufflen, sense, - timeout, retries, 0); -} static inline int scsi_device_online(struct scsi_device *sdev) { return sdev->sdev_state != SDEV_OFFLINE; From 820732b501a5bbdd3bde1263f391891e21b5ed8c Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sun, 12 Jun 2005 22:21:29 -0500 Subject: [PATCH 076/114] [SCSI] convert sr to scsi_execute_req This follows almost the identical model to sd, except that there's one ioctl which returns raw sense data, so it had to use scsi_execute() instead. Signed-off-by: James Bottomley --- drivers/scsi/sr.c | 49 +++++++------------------------- drivers/scsi/sr_ioctl.c | 62 ++++++++++++++++++----------------------- 2 files changed, 37 insertions(+), 74 deletions(-) diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 8cbe6e004187..39fc5b0fbc18 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -50,10 +50,10 @@ #include #include #include +#include #include #include #include /* For the door lock/unlock commands */ -#include #include "scsi_logging.h" #include "sr.h" @@ -658,39 +658,27 @@ static void get_sectorsize(struct scsi_cd *cd) unsigned char *buffer; int the_result, retries = 3; int sector_size; - struct scsi_request *SRpnt = NULL; request_queue_t *queue; buffer = kmalloc(512, GFP_KERNEL | GFP_DMA); if (!buffer) goto Enomem; - SRpnt = scsi_allocate_request(cd->device, GFP_KERNEL); - if (!SRpnt) - goto Enomem; do { cmd[0] = READ_CAPACITY; memset((void *) &cmd[1], 0, 9); - /* Mark as really busy */ - SRpnt->sr_request->rq_status = RQ_SCSI_BUSY; - SRpnt->sr_cmd_len = 0; - memset(buffer, 0, 8); /* Do the command and wait.. */ - SRpnt->sr_data_direction = DMA_FROM_DEVICE; - scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer, - 8, SR_TIMEOUT, MAX_RETRIES); + the_result = scsi_execute_req(cd->device, cmd, DMA_FROM_DEVICE, + buffer, 8, NULL, SR_TIMEOUT, + MAX_RETRIES); - the_result = SRpnt->sr_result; retries--; } while (the_result && retries); - scsi_release_request(SRpnt); - SRpnt = NULL; - if (the_result) { cd->capacity = 0x1fffff; sector_size = 2048; /* A guess, just in case */ @@ -750,8 +738,6 @@ static void get_sectorsize(struct scsi_cd *cd) cd->capacity = 0x1fffff; sector_size = 2048; /* A guess, just in case */ cd->needs_sector_size = 1; - if (SRpnt) - scsi_release_request(SRpnt); goto out; } @@ -759,8 +745,8 @@ static void get_capabilities(struct scsi_cd *cd) { unsigned char *buffer; struct scsi_mode_data data; - struct scsi_request *SRpnt; unsigned char cmd[MAX_COMMAND_SIZE]; + struct scsi_sense_hdr sshdr; unsigned int the_result; int retries, rc, n; @@ -776,19 +762,11 @@ static void get_capabilities(struct scsi_cd *cd) "" }; - /* allocate a request for the TEST_UNIT_READY */ - SRpnt = scsi_allocate_request(cd->device, GFP_KERNEL); - if (!SRpnt) { - printk(KERN_WARNING "(get_capabilities:) Request allocation " - "failure.\n"); - return; - } /* allocate transfer buffer */ buffer = kmalloc(512, GFP_KERNEL | GFP_DMA); if (!buffer) { printk(KERN_ERR "sr: out of memory.\n"); - scsi_release_request(SRpnt); return; } @@ -800,20 +778,15 @@ static void get_capabilities(struct scsi_cd *cd) memset((void *)cmd, 0, MAX_COMMAND_SIZE); cmd[0] = TEST_UNIT_READY; - SRpnt->sr_cmd_len = 0; - SRpnt->sr_sense_buffer[0] = 0; - SRpnt->sr_sense_buffer[2] = 0; - SRpnt->sr_data_direction = DMA_NONE; + the_result = scsi_execute_req (cd->device, cmd, DMA_NONE, NULL, + 0, &sshdr, SR_TIMEOUT, + MAX_RETRIES); - scsi_wait_req (SRpnt, (void *) cmd, buffer, - 0, SR_TIMEOUT, MAX_RETRIES); - - the_result = SRpnt->sr_result; retries++; } while (retries < 5 && (!scsi_status_is_good(the_result) || - ((driver_byte(the_result) & DRIVER_SENSE) && - SRpnt->sr_sense_buffer[2] == UNIT_ATTENTION))); + (scsi_sense_valid(&sshdr) && + sshdr.sense_key == UNIT_ATTENTION))); /* ask for mode page 0x2a */ rc = scsi_mode_sense(cd->device, 0, 0x2a, buffer, 128, @@ -825,7 +798,6 @@ static void get_capabilities(struct scsi_cd *cd) cd->cdi.mask |= (CDC_CD_R | CDC_CD_RW | CDC_DVD_R | CDC_DVD | CDC_DVD_RAM | CDC_SELECT_DISC | CDC_SELECT_SPEED); - scsi_release_request(SRpnt); kfree(buffer); printk("%s: scsi-1 drive\n", cd->cdi.name); return; @@ -885,7 +857,6 @@ static void get_capabilities(struct scsi_cd *cd) cd->device->writeable = 1; } - scsi_release_request(SRpnt); kfree(buffer); } diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c index 82d68fdb1548..6e45ac3c43c5 100644 --- a/drivers/scsi/sr_ioctl.c +++ b/drivers/scsi/sr_ioctl.c @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include "sr.h" @@ -84,41 +84,37 @@ static int sr_fake_playtrkind(struct cdrom_device_info *cdi, struct cdrom_ti *ti int sr_do_ioctl(Scsi_CD *cd, struct packet_command *cgc) { - struct scsi_request *SRpnt; struct scsi_device *SDev; - struct request *req; + struct scsi_sense_hdr sshdr; int result, err = 0, retries = 0; + struct request_sense *sense = cgc->sense; SDev = cd->device; - SRpnt = scsi_allocate_request(SDev, GFP_KERNEL); - if (!SRpnt) { - printk(KERN_ERR "Unable to allocate SCSI request in sr_do_ioctl"); - err = -ENOMEM; - goto out; - } - SRpnt->sr_data_direction = cgc->data_direction; + + if (!sense) { + sense = kmalloc(sizeof(*sense), GFP_KERNEL); + if (!sense) { + err = -ENOMEM; + goto out; + } + } retry: if (!scsi_block_when_processing_errors(SDev)) { err = -ENODEV; - goto out_free; + goto out; } - scsi_wait_req(SRpnt, cgc->cmd, cgc->buffer, cgc->buflen, - cgc->timeout, IOCTL_RETRIES); + memset(sense, 0, sizeof(*sense)); + result = scsi_execute(SDev, cgc->cmd, cgc->data_direction, + cgc->buffer, cgc->buflen, (char *)sense, + cgc->timeout, IOCTL_RETRIES, 0); - req = SRpnt->sr_request; - if (SRpnt->sr_buffer && req->buffer && SRpnt->sr_buffer != req->buffer) { - memcpy(req->buffer, SRpnt->sr_buffer, SRpnt->sr_bufflen); - kfree(SRpnt->sr_buffer); - SRpnt->sr_buffer = req->buffer; - } - - result = SRpnt->sr_result; + scsi_normalize_sense((char *)sense, sizeof(*sense), &sshdr); /* Minimal error checking. Ignore cases we know about, and report the rest. */ if (driver_byte(result) != 0) { - switch (SRpnt->sr_sense_buffer[2] & 0xf) { + switch (sshdr.sense_key) { case UNIT_ATTENTION: SDev->changed = 1; if (!cgc->quiet) @@ -128,8 +124,8 @@ int sr_do_ioctl(Scsi_CD *cd, struct packet_command *cgc) err = -ENOMEDIUM; break; case NOT_READY: /* This happens if there is no disc in drive */ - if (SRpnt->sr_sense_buffer[12] == 0x04 && - SRpnt->sr_sense_buffer[13] == 0x01) { + if (sshdr.asc == 0x04 && + sshdr.ascq == 0x01) { /* sense: Logical unit is in process of becoming ready */ if (!cgc->quiet) printk(KERN_INFO "%s: CDROM not ready yet.\n", cd->cdi.name); @@ -146,37 +142,33 @@ int sr_do_ioctl(Scsi_CD *cd, struct packet_command *cgc) if (!cgc->quiet) printk(KERN_INFO "%s: CDROM not ready. Make sure there is a disc in the drive.\n", cd->cdi.name); #ifdef DEBUG - scsi_print_req_sense("sr", SRpnt); + scsi_print_sense_hdr("sr", &sshdr); #endif err = -ENOMEDIUM; break; case ILLEGAL_REQUEST: err = -EIO; - if (SRpnt->sr_sense_buffer[12] == 0x20 && - SRpnt->sr_sense_buffer[13] == 0x00) + if (sshdr.asc == 0x20 && + sshdr.ascq == 0x00) /* sense: Invalid command operation code */ err = -EDRIVE_CANT_DO_THIS; #ifdef DEBUG __scsi_print_command(cgc->cmd); - scsi_print_req_sense("sr", SRpnt); + scsi_print_sense_hdr("sr", &sshdr); #endif break; default: printk(KERN_ERR "%s: CDROM (ioctl) error, command: ", cd->cdi.name); __scsi_print_command(cgc->cmd); - scsi_print_req_sense("sr", SRpnt); + scsi_print_sense_hdr("sr", &sshdr); err = -EIO; } } - if (cgc->sense) - memcpy(cgc->sense, SRpnt->sr_sense_buffer, sizeof(*cgc->sense)); - /* Wake up a process waiting for device */ - out_free: - scsi_release_request(SRpnt); - SRpnt = NULL; out: + if (!cgc->sense) + kfree(sense); cgc->stat = err; return err; } From 84743bbcf9fc3767aa33f769898432538281e6dc Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sun, 12 Jun 2005 22:37:10 -0500 Subject: [PATCH 077/114] [SCSI] convert ch to use scsi_execute_req I also tinkered with it's sense recognition routines to make them take scsi_sense_hdr structures instead of raw sense data. Signed-off-by: James Bottomley --- drivers/scsi/ch.c | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c index 53b395534313..bd0e1b6be1ea 100644 --- a/drivers/scsi/ch.c +++ b/drivers/scsi/ch.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #define CH_DT_MAX 16 @@ -180,17 +180,17 @@ static struct { /* ------------------------------------------------------------------- */ -static int ch_find_errno(unsigned char *sense_buffer) +static int ch_find_errno(struct scsi_sense_hdr *sshdr) { int i,errno = 0; /* Check to see if additional sense information is available */ - if (sense_buffer[7] > 5 && - sense_buffer[12] != 0) { + if (scsi_sense_valid(sshdr) && + sshdr->asc != 0) { for (i = 0; err[i].errno != 0; i++) { - if (err[i].sense == sense_buffer[ 2] && - err[i].asc == sense_buffer[12] && - err[i].ascq == sense_buffer[13]) { + if (err[i].sense == sshdr->sense_key && + err[i].asc == sshdr->asc && + err[i].ascq == sshdr->ascq) { errno = -err[i].errno; break; } @@ -206,13 +206,9 @@ ch_do_scsi(scsi_changer *ch, unsigned char *cmd, void *buffer, unsigned buflength, enum dma_data_direction direction) { - int errno, retries = 0, timeout; - struct scsi_request *sr; + int errno, retries = 0, timeout, result; + struct scsi_sense_hdr sshdr; - sr = scsi_allocate_request(ch->device, GFP_KERNEL); - if (NULL == sr) - return -ENOMEM; - timeout = (cmd[0] == INITIALIZE_ELEMENT_STATUS) ? timeout_init : timeout_move; @@ -223,16 +219,17 @@ ch_do_scsi(scsi_changer *ch, unsigned char *cmd, __scsi_print_command(cmd); } - scsi_wait_req(sr, cmd, buffer, buflength, - timeout * HZ, MAX_RETRIES); + result = scsi_execute_req(ch->device, cmd, direction, buffer, + buflength, &sshdr, timeout * HZ, + MAX_RETRIES); - dprintk("result: 0x%x\n",sr->sr_result); - if (driver_byte(sr->sr_result) & DRIVER_SENSE) { + dprintk("result: 0x%x\n",result); + if (driver_byte(result) & DRIVER_SENSE) { if (debug) - scsi_print_req_sense(ch->name, sr); - errno = ch_find_errno(sr->sr_sense_buffer); + scsi_print_sense_hdr(ch->name, &sshdr); + errno = ch_find_errno(&sshdr); - switch(sr->sr_sense_buffer[2] & 0xf) { + switch(sshdr.sense_key) { case UNIT_ATTENTION: ch->unit_attention = 1; if (retries++ < 3) @@ -240,7 +237,6 @@ ch_do_scsi(scsi_changer *ch, unsigned char *cmd, break; } } - scsi_release_request(sr); return errno; } From 1ccb48bb163853c24840c0a50c2a6df1affe029c Mon Sep 17 00:00:00 2001 From: "akpm@osdl.org" Date: Sun, 26 Jun 2005 00:12:51 -0700 Subject: [PATCH 078/114] [SCSI] fix C syntax problem in scsi_lib.c Older gcc's require variable definitions at the beginning of a block. Signed-off-by: Andrew Morton Signed-off-by: James Bottomley --- drivers/scsi/scsi_lib.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index bdea26b56dc4..58da7f64c22f 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -336,14 +336,15 @@ int scsi_execute_req(struct scsi_device *sdev, const unsigned char *cmd, struct scsi_sense_hdr *sshdr, int timeout, int retries) { char *sense = NULL; - + int result; + if (sshdr) { sense = kmalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL); if (!sense) return DRIVER_ERROR << 24; memset(sense, 0, sizeof(*sense)); } - int result = scsi_execute(sdev, cmd, data_direction, buffer, bufflen, + result = scsi_execute(sdev, cmd, data_direction, buffer, bufflen, sense, timeout, retries, 0); if (sshdr) scsi_normalize_sense(sense, sizeof(*sense), sshdr); From f189c5cb8ddde0c01838f2b3bc7650e86c097a14 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Sun, 19 Jun 2005 11:32:53 +0200 Subject: [PATCH 079/114] [SCSI] comment cleanup for spi_execute Signed-off-by: James Bottomley --- drivers/scsi/scsi_transport_spi.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c index 874042f1899d..ef577c8c2182 100644 --- a/drivers/scsi/scsi_transport_spi.c +++ b/drivers/scsi/scsi_transport_spi.c @@ -106,8 +106,6 @@ static int sprint_frac(char *dest, int value, int denom) return result; } -/* Modification of scsi_wait_req that will clear UNIT ATTENTION conditions - * resulting from (likely) bus and device resets */ static int spi_execute(struct scsi_device *sdev, const void *cmd, enum dma_data_direction dir, void *buffer, unsigned bufflen, @@ -117,8 +115,6 @@ static int spi_execute(struct scsi_device *sdev, const void *cmd, unsigned char sense[SCSI_SENSE_BUFFERSIZE]; for(i = 0; i < DV_RETRIES; i++) { - - /* FIXME: need to set REQ_FAILFAST */ result = scsi_execute(sdev, cmd, dir, buffer, bufflen, sense, DV_TIMEOUT, /* retries */ 1, REQ_FAILFAST); From c9d297c543f379a27a34082070ed03a8ef846fc2 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Tue, 28 Jun 2005 09:18:21 -0500 Subject: [PATCH 080/114] [SCSI] fix 3ware raid emulated commands The 3ware emulated commands all expect they are executing in the use_sg == 0 case, which isn't true either in the block layer rework or an SG_IO ioctl. Fix this by adding the correct kmapping of the first element in the sg list. Signed-off-by: James Bottomley --- drivers/scsi/3w-xxxx.c | 57 +++++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 18 deletions(-) diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index 973c51fb0fe2..ae9e0203e9de 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c @@ -1499,22 +1499,43 @@ static int tw_scsiop_inquiry(TW_Device_Extension *tw_dev, int request_id) return 0; } /* End tw_scsiop_inquiry() */ +static void tw_transfer_internal(TW_Device_Extension *tw_dev, int request_id, + void *data, unsigned int len) +{ + struct scsi_cmnd *cmd = tw_dev->srb[request_id]; + void *buf; + unsigned int transfer_len; + + if (cmd->use_sg) { + struct scatterlist *sg = + (struct scatterlist *)cmd->request_buffer; + buf = kmap_atomic(sg->page, KM_IRQ0) + sg->offset; + transfer_len = min(sg->length, len); + } else { + buf = cmd->request_buffer; + transfer_len = min(cmd->request_bufflen, len); + } + + memcpy(buf, data, transfer_len); + + if (cmd->use_sg) { + struct scatterlist *sg; + + sg = (struct scatterlist *)cmd->request_buffer; + kunmap_atomic(buf - sg->offset, KM_IRQ0); + } +} + /* This function is called by the isr to complete an inquiry command */ static int tw_scsiop_inquiry_complete(TW_Device_Extension *tw_dev, int request_id) { unsigned char *is_unit_present; - unsigned char *request_buffer; + unsigned char request_buffer[36]; TW_Param *param; dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_inquiry_complete()\n"); - /* Fill request buffer */ - if (tw_dev->srb[request_id]->request_buffer == NULL) { - printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry_complete(): Request buffer NULL.\n"); - return 1; - } - request_buffer = tw_dev->srb[request_id]->request_buffer; - memset(request_buffer, 0, tw_dev->srb[request_id]->request_bufflen); + memset(request_buffer, 0, sizeof(request_buffer)); request_buffer[0] = TYPE_DISK; /* Peripheral device type */ request_buffer[1] = 0; /* Device type modifier */ request_buffer[2] = 0; /* No ansi/iso compliance */ @@ -1522,6 +1543,8 @@ static int tw_scsiop_inquiry_complete(TW_Device_Extension *tw_dev, int request_i memcpy(&request_buffer[8], "3ware ", 8); /* Vendor ID */ sprintf(&request_buffer[16], "Logical Disk %-2d ", tw_dev->srb[request_id]->device->id); memcpy(&request_buffer[32], TW_DRIVER_VERSION, 3); + tw_transfer_internal(tw_dev, request_id, request_buffer, + sizeof(request_buffer)); param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; if (param == NULL) { @@ -1612,7 +1635,7 @@ static int tw_scsiop_mode_sense_complete(TW_Device_Extension *tw_dev, int reques { TW_Param *param; unsigned char *flags; - unsigned char *request_buffer; + unsigned char request_buffer[8]; dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_mode_sense_complete()\n"); @@ -1622,8 +1645,7 @@ static int tw_scsiop_mode_sense_complete(TW_Device_Extension *tw_dev, int reques return 1; } flags = (char *)&(param->data[0]); - request_buffer = tw_dev->srb[request_id]->buffer; - memset(request_buffer, 0, tw_dev->srb[request_id]->request_bufflen); + memset(request_buffer, 0, sizeof(request_buffer)); request_buffer[0] = 0xf; /* mode data length */ request_buffer[1] = 0; /* default medium type */ @@ -1635,6 +1657,8 @@ static int tw_scsiop_mode_sense_complete(TW_Device_Extension *tw_dev, int reques request_buffer[6] = 0x4; /* WCE on */ else request_buffer[6] = 0x0; /* WCE off */ + tw_transfer_internal(tw_dev, request_id, request_buffer, + sizeof(request_buffer)); return 0; } /* End tw_scsiop_mode_sense_complete() */ @@ -1701,17 +1725,12 @@ static int tw_scsiop_read_capacity_complete(TW_Device_Extension *tw_dev, int req { unsigned char *param_data; u32 capacity; - char *buff; + char buff[8]; TW_Param *param; dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity_complete()\n"); - buff = tw_dev->srb[request_id]->request_buffer; - if (buff == NULL) { - printk(KERN_WARNING "3w-xxxx: tw_scsiop_read_capacity_complete(): Request buffer NULL.\n"); - return 1; - } - memset(buff, 0, tw_dev->srb[request_id]->request_bufflen); + memset(buff, 0, sizeof(buff)); param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; if (param == NULL) { printk(KERN_WARNING "3w-xxxx: tw_scsiop_read_capacity_complete(): Bad alignment virtual address.\n"); @@ -1739,6 +1758,8 @@ static int tw_scsiop_read_capacity_complete(TW_Device_Extension *tw_dev, int req buff[6] = (TW_BLOCK_SIZE >> 8) & 0xff; buff[7] = TW_BLOCK_SIZE & 0xff; + tw_transfer_internal(tw_dev, request_id, buff, sizeof(buff)); + return 0; } /* End tw_scsiop_read_capacity_complete() */ From e514385be2b355c1f3fc6385a98a6a0fc04235ae Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Tue, 9 Aug 2005 11:55:36 -0500 Subject: [PATCH 081/114] [SCSI] fix sense buffer length handling problem The new bio code was incorrectly converted from stack allocated to kmalloc'd buffer handling. There are two places where it incorrectly uses sizeof(*sense) to get the size of the sense buffer. This actually produces one, so no sense data was ever getting back, causing failure in things like disk spin up. Signed-off-by: James Bottomley --- drivers/scsi/scsi_lib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 58da7f64c22f..72a47ce7a1d3 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -342,12 +342,12 @@ int scsi_execute_req(struct scsi_device *sdev, const unsigned char *cmd, sense = kmalloc(SCSI_SENSE_BUFFERSIZE, GFP_KERNEL); if (!sense) return DRIVER_ERROR << 24; - memset(sense, 0, sizeof(*sense)); + memset(sense, 0, SCSI_SENSE_BUFFERSIZE); } result = scsi_execute(sdev, cmd, data_direction, buffer, bufflen, sense, timeout, retries, 0); if (sshdr) - scsi_normalize_sense(sense, sizeof(*sense), sshdr); + scsi_normalize_sense(sense, SCSI_SENSE_BUFFERSIZE, sshdr); kfree(sense); return result; From 53c165e0a6c8a4ff7df316557528fa7a52d20711 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Mon, 22 Aug 2005 10:06:19 -0500 Subject: [PATCH 082/114] [SCSI] correct attribute_container list usage One of the changes in the attribute_container code in the scsi-misc tree was to add a lock to protect the list of devices per container. This, unfortunately, leads to potential scheduling while atomic problems if there's a sleep in the function called by a trigger. The correct solution is to use the kernel klist infrastructure instead which allows lockless traversal of a list. Signed-off-by: James Bottomley --- drivers/base/attribute_container.c | 51 ++++++++++++++++------------- include/linux/attribute_container.h | 4 +-- 2 files changed, 31 insertions(+), 24 deletions(-) diff --git a/drivers/base/attribute_container.c b/drivers/base/attribute_container.c index ebcae5c34133..6c0f49340eb2 100644 --- a/drivers/base/attribute_container.c +++ b/drivers/base/attribute_container.c @@ -22,7 +22,7 @@ /* This is a private structure used to tie the classdev and the * container .. it should never be visible outside this file */ struct internal_container { - struct list_head node; + struct klist_node node; struct attribute_container *cont; struct class_device classdev; }; @@ -57,8 +57,7 @@ int attribute_container_register(struct attribute_container *cont) { INIT_LIST_HEAD(&cont->node); - INIT_LIST_HEAD(&cont->containers); - spin_lock_init(&cont->containers_lock); + klist_init(&cont->containers); down(&attribute_container_mutex); list_add_tail(&cont->node, &attribute_container_list); @@ -78,13 +77,13 @@ attribute_container_unregister(struct attribute_container *cont) { int retval = -EBUSY; down(&attribute_container_mutex); - spin_lock(&cont->containers_lock); - if (!list_empty(&cont->containers)) + spin_lock(&cont->containers.k_lock); + if (!list_empty(&cont->containers.k_list)) goto out; retval = 0; list_del(&cont->node); out: - spin_unlock(&cont->containers_lock); + spin_unlock(&cont->containers.k_lock); up(&attribute_container_mutex); return retval; @@ -143,7 +142,6 @@ attribute_container_add_device(struct device *dev, continue; } memset(ic, 0, sizeof(struct internal_container)); - INIT_LIST_HEAD(&ic->node); ic->cont = cont; class_device_initialize(&ic->classdev); ic->classdev.dev = get_device(dev); @@ -154,13 +152,22 @@ attribute_container_add_device(struct device *dev, fn(cont, dev, &ic->classdev); else attribute_container_add_class_device(&ic->classdev); - spin_lock(&cont->containers_lock); - list_add_tail(&ic->node, &cont->containers); - spin_unlock(&cont->containers_lock); + klist_add_tail(&ic->node, &cont->containers); } up(&attribute_container_mutex); } +/* FIXME: can't break out of this unless klist_iter_exit is also + * called before doing the break + */ +#define klist_for_each_entry(pos, head, member, iter) \ + for (klist_iter_init(head, iter); (pos = ({ \ + struct klist_node *n = klist_next(iter); \ + n ? ({ klist_iter_exit(iter) ; NULL; }) : \ + container_of(n, typeof(*pos), member);\ + }) ) != NULL; ) + + /** * attribute_container_remove_device - make device eligible for removal. * @@ -187,18 +194,19 @@ attribute_container_remove_device(struct device *dev, down(&attribute_container_mutex); list_for_each_entry(cont, &attribute_container_list, node) { - struct internal_container *ic, *tmp; + struct internal_container *ic; + struct klist_iter iter; if (attribute_container_no_classdevs(cont)) continue; if (!cont->match(cont, dev)) continue; - spin_lock(&cont->containers_lock); - list_for_each_entry_safe(ic, tmp, &cont->containers, node) { + + klist_for_each_entry(ic, &cont->containers, node, &iter) { if (dev != ic->classdev.dev) continue; - list_del(&ic->node); + klist_remove(&ic->node); if (fn) fn(cont, dev, &ic->classdev); else { @@ -206,7 +214,6 @@ attribute_container_remove_device(struct device *dev, class_device_unregister(&ic->classdev); } } - spin_unlock(&cont->containers_lock); } up(&attribute_container_mutex); } @@ -232,7 +239,8 @@ attribute_container_device_trigger(struct device *dev, down(&attribute_container_mutex); list_for_each_entry(cont, &attribute_container_list, node) { - struct internal_container *ic, *tmp; + struct internal_container *ic; + struct klist_iter iter; if (!cont->match(cont, dev)) continue; @@ -242,12 +250,10 @@ attribute_container_device_trigger(struct device *dev, continue; } - spin_lock(&cont->containers_lock); - list_for_each_entry_safe(ic, tmp, &cont->containers, node) { + klist_for_each_entry(ic, &cont->containers, node, &iter) { if (dev == ic->classdev.dev) fn(cont, dev, &ic->classdev); } - spin_unlock(&cont->containers_lock); } up(&attribute_container_mutex); } @@ -397,15 +403,16 @@ attribute_container_find_class_device(struct attribute_container *cont, { struct class_device *cdev = NULL; struct internal_container *ic; + struct klist_iter iter; - spin_lock(&cont->containers_lock); - list_for_each_entry(ic, &cont->containers, node) { + klist_for_each_entry(ic, &cont->containers, node, &iter) { if (ic->classdev.dev == dev) { cdev = &ic->classdev; + /* FIXME: must exit iterator then break */ + klist_iter_exit(&iter); break; } } - spin_unlock(&cont->containers_lock); return cdev; } diff --git a/include/linux/attribute_container.h b/include/linux/attribute_container.h index ee83fe64a102..93bfb0beb62a 100644 --- a/include/linux/attribute_container.h +++ b/include/linux/attribute_container.h @@ -11,12 +11,12 @@ #include #include +#include #include struct attribute_container { struct list_head node; - struct list_head containers; - spinlock_t containers_lock; + struct klist containers; struct class *class; struct class_device_attribute **attrs; int (*match)(struct attribute_container *, struct device *); From 2b7d6a8cb9718fc1d9e826201b64909c44a915f4 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sun, 28 Aug 2005 09:13:17 -0500 Subject: [PATCH 083/114] [SCSI] attribute container final klist fixes Since the attribute container deletes from a klist while it's walking it, it is vulnerable to the problem (and fix) here: http://marc.theaimsgroup.com/?l=linux-scsi&m=112485448830217 The attached fixes this (but won't compile without the above). It also fixes the logical reversal in the traversal loop which meant that we were never actually traversing the loop to hit this bug in the first place. Signed-off-by: James Bottomley --- drivers/base/attribute_container.c | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/drivers/base/attribute_container.c b/drivers/base/attribute_container.c index 6c0f49340eb2..373e7b728fa7 100644 --- a/drivers/base/attribute_container.c +++ b/drivers/base/attribute_container.c @@ -27,6 +27,21 @@ struct internal_container { struct class_device classdev; }; +static void internal_container_klist_get(struct klist_node *n) +{ + struct internal_container *ic = + container_of(n, struct internal_container, node); + class_device_get(&ic->classdev); +} + +static void internal_container_klist_put(struct klist_node *n) +{ + struct internal_container *ic = + container_of(n, struct internal_container, node); + class_device_put(&ic->classdev); +} + + /** * attribute_container_classdev_to_container - given a classdev, return the container * @@ -57,7 +72,8 @@ int attribute_container_register(struct attribute_container *cont) { INIT_LIST_HEAD(&cont->node); - klist_init(&cont->containers); + klist_init(&cont->containers,internal_container_klist_get, + internal_container_klist_put); down(&attribute_container_mutex); list_add_tail(&cont->node, &attribute_container_list); @@ -163,8 +179,8 @@ attribute_container_add_device(struct device *dev, #define klist_for_each_entry(pos, head, member, iter) \ for (klist_iter_init(head, iter); (pos = ({ \ struct klist_node *n = klist_next(iter); \ - n ? ({ klist_iter_exit(iter) ; NULL; }) : \ - container_of(n, typeof(*pos), member);\ + n ? container_of(n, typeof(*pos), member) : \ + ({ klist_iter_exit(iter) ; NULL; }); \ }) ) != NULL; ) @@ -206,7 +222,7 @@ attribute_container_remove_device(struct device *dev, klist_for_each_entry(ic, &cont->containers, node, &iter) { if (dev != ic->classdev.dev) continue; - klist_remove(&ic->node); + klist_del(&ic->node); if (fn) fn(cont, dev, &ic->classdev); else { From 61a7afa2c476a3be261cf88a95b0dea0c3bd29d4 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Tue, 16 Aug 2005 18:27:34 -0500 Subject: [PATCH 084/114] [SCSI] embryonic RAID class The idea behind a RAID class is to provide a uniform interface to all RAID subsystems (both hardware and software) in the kernel. To do that, I've made this class a transport class that's entirely subsystem independent (although the matching routines have to match per subsystem, as you'll see looking at the code). I put it in the scsi subdirectory purely because I needed somewhere to play with it, but it's not a scsi specific module. I used a fusion raid card as the test bed for this; with that kind of card, this is the type of class output you get: jejb@titanic> ls -l /sys/class/raid_devices/20\:0\:0\:0/ total 0 lrwxrwxrwx 1 root root 0 Aug 16 17:21 component-0 -> ../../../devices/pci0000:80/0000:80:04.0/host20/target20:1:0/20:1:0:0/ lrwxrwxrwx 1 root root 0 Aug 16 17:21 component-1 -> ../../../devices/pci0000:80/0000:80:04.0/host20/target20:1:1/20:1:1:0/ lrwxrwxrwx 1 root root 0 Aug 16 17:21 device -> ../../../devices/pci0000:80/0000:80:04.0/host20/target20:0:0/20:0:0:0/ -r--r--r-- 1 root root 16384 Aug 16 17:21 level -r--r--r-- 1 root root 16384 Aug 16 17:21 resync -r--r--r-- 1 root root 16384 Aug 16 17:21 state So it's really simple: for a SCSI device representing a hardware raid, it shows the raid level, the array state, the resync % complete (if the state is resyncing) and the underlying components of the RAID (these are exposed in fusion on the virtual channel 1). As you can see, this type of information can be exported by almost anything, including software raid. The more difficult trick, of course, is going to be getting it to perform configuration type actions with writable attributes. Signed-off-by: James Bottomley --- drivers/scsi/Kconfig | 6 + drivers/scsi/Makefile | 2 + drivers/scsi/raid_class.c | 250 +++++++++++++++++++++++++++++++++++++ include/linux/raid_class.h | 59 +++++++++ 4 files changed, 317 insertions(+) create mode 100644 drivers/scsi/raid_class.c create mode 100644 include/linux/raid_class.h diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 96df148ed969..68adc3cc8ad2 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -1,5 +1,11 @@ menu "SCSI device support" +config RAID_ATTRS + tristate "RAID Transport Class" + default n + ---help--- + Provides RAID + config SCSI tristate "SCSI device support" ---help--- diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 3746fb9fa2f5..85f9e6bb34b9 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -22,6 +22,8 @@ subdir-$(CONFIG_PCMCIA) += pcmcia obj-$(CONFIG_SCSI) += scsi_mod.o +obj-$(CONFIG_RAID_ATTRS) += raid_class.o + # --- NOTE ORDERING HERE --- # For kernel non-modular link, transport attributes need to # be initialised before drivers diff --git a/drivers/scsi/raid_class.c b/drivers/scsi/raid_class.c new file mode 100644 index 000000000000..f1ea5027865f --- /dev/null +++ b/drivers/scsi/raid_class.c @@ -0,0 +1,250 @@ +/* + * RAID Attributes + */ +#include +#include +#include +#include +#include +#include + +#define RAID_NUM_ATTRS 3 + +struct raid_internal { + struct raid_template r; + struct raid_function_template *f; + /* The actual attributes */ + struct class_device_attribute private_attrs[RAID_NUM_ATTRS]; + /* The array of null terminated pointers to attributes + * needed by scsi_sysfs.c */ + struct class_device_attribute *attrs[RAID_NUM_ATTRS + 1]; +}; + +struct raid_component { + struct list_head node; + struct device *dev; + int num; +}; + +#define to_raid_internal(tmpl) container_of(tmpl, struct raid_internal, r) + +#define tc_to_raid_internal(tcont) ({ \ + struct raid_template *r = \ + container_of(tcont, struct raid_template, raid_attrs); \ + to_raid_internal(r); \ +}) + +#define ac_to_raid_internal(acont) ({ \ + struct transport_container *tc = \ + container_of(acont, struct transport_container, ac); \ + tc_to_raid_internal(tc); \ +}) + +#define class_device_to_raid_internal(cdev) ({ \ + struct attribute_container *ac = \ + attribute_container_classdev_to_container(cdev); \ + ac_to_raid_internal(ac); \ +}) + + +static int raid_match(struct attribute_container *cont, struct device *dev) +{ + /* We have to look for every subsystem that could house + * emulated RAID devices, so start with SCSI */ + struct raid_internal *i = ac_to_raid_internal(cont); + + if (scsi_is_sdev_device(dev)) { + struct scsi_device *sdev = to_scsi_device(dev); + + if (i->f->cookie != sdev->host->hostt) + return 0; + + return i->f->is_raid(dev); + } + /* FIXME: look at other subsystems too */ + return 0; +} + +static int raid_setup(struct transport_container *tc, struct device *dev, + struct class_device *cdev) +{ + struct raid_data *rd; + + BUG_ON(class_get_devdata(cdev)); + + rd = kmalloc(sizeof(*rd), GFP_KERNEL); + if (!rd) + return -ENOMEM; + + memset(rd, 0, sizeof(*rd)); + INIT_LIST_HEAD(&rd->component_list); + class_set_devdata(cdev, rd); + + return 0; +} + +static int raid_remove(struct transport_container *tc, struct device *dev, + struct class_device *cdev) +{ + struct raid_data *rd = class_get_devdata(cdev); + struct raid_component *rc, *next; + class_set_devdata(cdev, NULL); + list_for_each_entry_safe(rc, next, &rd->component_list, node) { + char buf[40]; + snprintf(buf, sizeof(buf), "component-%d", rc->num); + list_del(&rc->node); + sysfs_remove_link(&cdev->kobj, buf); + kfree(rc); + } + kfree(class_get_devdata(cdev)); + return 0; +} + +static DECLARE_TRANSPORT_CLASS(raid_class, + "raid_devices", + raid_setup, + raid_remove, + NULL); + +static struct { + enum raid_state value; + char *name; +} raid_states[] = { + { RAID_ACTIVE, "active" }, + { RAID_DEGRADED, "degraded" }, + { RAID_RESYNCING, "resyncing" }, + { RAID_OFFLINE, "offline" }, +}; + +static const char *raid_state_name(enum raid_state state) +{ + int i; + char *name = NULL; + + for (i = 0; i < sizeof(raid_states)/sizeof(raid_states[0]); i++) { + if (raid_states[i].value == state) { + name = raid_states[i].name; + break; + } + } + return name; +} + + +#define raid_attr_show_internal(attr, fmt, var, code) \ +static ssize_t raid_show_##attr(struct class_device *cdev, char *buf) \ +{ \ + struct raid_data *rd = class_get_devdata(cdev); \ + code \ + return snprintf(buf, 20, #fmt "\n", var); \ +} + +#define raid_attr_ro_states(attr, states, code) \ +raid_attr_show_internal(attr, %s, name, \ + const char *name; \ + code \ + name = raid_##states##_name(rd->attr); \ +) \ +static CLASS_DEVICE_ATTR(attr, S_IRUGO, raid_show_##attr, NULL) + + +#define raid_attr_ro_internal(attr, code) \ +raid_attr_show_internal(attr, %d, rd->attr, code) \ +static CLASS_DEVICE_ATTR(attr, S_IRUGO, raid_show_##attr, NULL) + +#define ATTR_CODE(attr) \ + struct raid_internal *i = class_device_to_raid_internal(cdev); \ + if (i->f->get_##attr) \ + i->f->get_##attr(cdev->dev); + +#define raid_attr_ro(attr) raid_attr_ro_internal(attr, ) +#define raid_attr_ro_fn(attr) raid_attr_ro_internal(attr, ATTR_CODE(attr)) +#define raid_attr_ro_state(attr) raid_attr_ro_states(attr, attr, ATTR_CODE(attr)) + +raid_attr_ro(level); +raid_attr_ro_fn(resync); +raid_attr_ro_state(state); + +void raid_component_add(struct raid_template *r,struct device *raid_dev, + struct device *component_dev) +{ + struct class_device *cdev = + attribute_container_find_class_device(&r->raid_attrs.ac, + raid_dev); + struct raid_component *rc; + struct raid_data *rd = class_get_devdata(cdev); + char buf[40]; + + rc = kmalloc(sizeof(*rc), GFP_KERNEL); + if (!rc) + return; + + INIT_LIST_HEAD(&rc->node); + rc->dev = component_dev; + rc->num = rd->component_count++; + + snprintf(buf, sizeof(buf), "component-%d", rc->num); + list_add_tail(&rc->node, &rd->component_list); + sysfs_create_link(&cdev->kobj, &component_dev->kobj, buf); +} +EXPORT_SYMBOL(raid_component_add); + +struct raid_template * +raid_class_attach(struct raid_function_template *ft) +{ + struct raid_internal *i = kmalloc(sizeof(struct raid_internal), + GFP_KERNEL); + int count = 0; + + if (unlikely(!i)) + return NULL; + + memset(i, 0, sizeof(*i)); + + i->f = ft; + + i->r.raid_attrs.ac.class = &raid_class.class; + i->r.raid_attrs.ac.match = raid_match; + i->r.raid_attrs.ac.attrs = &i->attrs[0]; + + attribute_container_register(&i->r.raid_attrs.ac); + + i->attrs[count++] = &class_device_attr_level; + i->attrs[count++] = &class_device_attr_resync; + i->attrs[count++] = &class_device_attr_state; + + i->attrs[count] = NULL; + BUG_ON(count > RAID_NUM_ATTRS); + + return &i->r; +} +EXPORT_SYMBOL(raid_class_attach); + +void +raid_class_release(struct raid_template *r) +{ + struct raid_internal *i = to_raid_internal(r); + + attribute_container_unregister(&i->r.raid_attrs.ac); + + kfree(i); +} +EXPORT_SYMBOL(raid_class_release); + +static __init int raid_init(void) +{ + return transport_class_register(&raid_class); +} + +static __exit void raid_exit(void) +{ + transport_class_unregister(&raid_class); +} + +MODULE_AUTHOR("James Bottomley"); +MODULE_DESCRIPTION("RAID device class"); +MODULE_LICENSE("GPL"); + +module_init(raid_init); +module_exit(raid_exit); + diff --git a/include/linux/raid_class.h b/include/linux/raid_class.h new file mode 100644 index 000000000000..a71123c28272 --- /dev/null +++ b/include/linux/raid_class.h @@ -0,0 +1,59 @@ +/* + */ +#include + +struct raid_template { + struct transport_container raid_attrs; +}; + +struct raid_function_template { + void *cookie; + int (*is_raid)(struct device *); + void (*get_resync)(struct device *); + void (*get_state)(struct device *); +}; + +enum raid_state { + RAID_ACTIVE = 1, + RAID_DEGRADED, + RAID_RESYNCING, + RAID_OFFLINE, +}; + +struct raid_data { + struct list_head component_list; + int component_count; + int level; + enum raid_state state; + int resync; +}; + +#define DEFINE_RAID_ATTRIBUTE(type, attr) \ +static inline void \ +raid_set_##attr(struct raid_template *r, struct device *dev, type value) { \ + struct class_device *cdev = \ + attribute_container_find_class_device(&r->raid_attrs.ac, dev);\ + struct raid_data *rd; \ + BUG_ON(!cdev); \ + rd = class_get_devdata(cdev); \ + rd->attr = value; \ +} \ +static inline type \ +raid_get_##attr(struct raid_template *r, struct device *dev) { \ + struct class_device *cdev = \ + attribute_container_find_class_device(&r->raid_attrs.ac, dev);\ + struct raid_data *rd; \ + BUG_ON(!cdev); \ + rd = class_get_devdata(cdev); \ + return rd->attr; \ +} + +DEFINE_RAID_ATTRIBUTE(int, level) +DEFINE_RAID_ATTRIBUTE(int, resync) +DEFINE_RAID_ATTRIBUTE(enum raid_state, state) + +struct raid_template *raid_class_attach(struct raid_function_template *); +void raid_class_release(struct raid_template *); + +void raid_component_add(struct raid_template *, struct device *, + struct device *); From 07542b832309b93a2741cd162a391ab909f66438 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Wed, 31 Aug 2005 20:27:22 -0400 Subject: [PATCH 085/114] This patch fixes in st.c the bug in the signed/unsigned int comparison reported by Doug Gilbert and fixed by him in sg.c (see [PATCH] sg direct io/mmap oops). Doug fixed the comparison in sg.c. This fix for st.c does not touch the comparison but makes both arguments signed to remove the problem. The new code is adapted from linux/fs/bio.c. Signed-off-by: Kai Makisara Rejections fixed up and Signed-off-by: James Bottomley --- drivers/scsi/st.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 47a5698a712a..5325cf0ab197 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -17,7 +17,7 @@ Last modified: 18-JAN-1998 Richard Gooch Devfs support */ -static char *verstr = "20050802"; +static char *verstr = "20050830"; #include @@ -4444,12 +4444,12 @@ static int st_map_user_pages(struct scatterlist *sgl, const unsigned int max_pag static int sgl_map_user_pages(struct scatterlist *sgl, const unsigned int max_pages, unsigned long uaddr, size_t count, int rw) { + unsigned long end = (uaddr + count + PAGE_SIZE - 1) >> PAGE_SHIFT; + unsigned long start = uaddr >> PAGE_SHIFT; + const int nr_pages = end - start; int res, i, j; - unsigned int nr_pages; struct page **pages; - nr_pages = ((uaddr & ~PAGE_MASK) + count + ~PAGE_MASK) >> PAGE_SHIFT; - /* User attempted Overflow! */ if ((uaddr + count) < uaddr) return -EINVAL; From deb92b7ee98e8e580cafaa63bd1edbe6646877bc Mon Sep 17 00:00:00 2001 From: Douglas Gilbert Date: Thu, 1 Sep 2005 21:50:02 +1000 Subject: [PATCH 086/114] [SCSI] sg direct io/mmap oops, st sync This patch adopts the same solution as proposed by Kai M. in a post titled: "[PATCH] SCSI tape signed/unsigned fix". The fix is in a function that the sg driver borrowed from the st driver so its maintenance is a little easier if the functions remain the same after the fix. - change nr_pages type from unsigned to signed so errors from get_user_pages() call are properly handled Signed-off-by: Douglas Gilbert Signed-off-by: James Bottomley --- drivers/scsi/sg.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 14fb179b3842..616c3f3e62fc 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -61,7 +61,7 @@ static int sg_version_num = 30533; /* 2 digits for each component */ #ifdef CONFIG_SCSI_PROC_FS #include -static char *sg_version_date = "20050328"; +static char *sg_version_date = "20050901"; static int sg_proc_init(void); static void sg_proc_cleanup(void); @@ -1794,12 +1794,12 @@ st_map_user_pages(struct scatterlist *sgl, const unsigned int max_pages, unsigned long uaddr, size_t count, int rw, unsigned long max_pfn) { + unsigned long end = (uaddr + count + PAGE_SIZE - 1) >> PAGE_SHIFT; + unsigned long start = uaddr >> PAGE_SHIFT; + const int nr_pages = end - start; int res, i, j; - unsigned int nr_pages; struct page **pages; - nr_pages = ((uaddr & ~PAGE_MASK) + count + ~PAGE_MASK) >> PAGE_SHIFT; - /* User attempted Overflow! */ if ((uaddr + count) < uaddr) return -EINVAL; From 77d71d222e871670300f3e3092e2a06f20c842f0 Mon Sep 17 00:00:00 2001 From: Mark Haverkamp Date: Thu, 1 Sep 2005 08:19:23 -0700 Subject: [PATCH 087/114] [SCSI] aacraid: bad BUG_ON fix This was noticed by Doug Bazamic and the fix found by Mark Salyzyn at Adaptec. There was an error in the BUG_ON() statement that validated the calculated fib size which can cause the driver to panic. Signed-off-by: Mark Haverkamp Signed-off-by: James Bottomley --- drivers/scsi/aacraid/aachba.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index 83bfab73ff65..a8e3dfcd0dc7 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -972,7 +972,7 @@ static int aac_read(struct scsi_cmnd * scsicmd, int cid) fibsize = sizeof(struct aac_read64) + ((le32_to_cpu(readcmd->sg.count) - 1) * sizeof (struct sgentry64)); - BUG_ON (fibsize > (sizeof(struct hw_fib) - + BUG_ON (fibsize > (dev->max_fib_size - sizeof(struct aac_fibhdr))); /* * Now send the Fib to the adapter From 1ff927306e08b356d764e605eff7c50079550bd2 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 19 Aug 2005 18:57:13 +0200 Subject: [PATCH 088/114] [SCSI] aic7xxx: remove aiclib.c #include of C files and macro tricks to rename symbols are evil and just cause trouble. Let's doublicate the two functions as they're going to go away soon enough anyway. Signed-off-by: James Bottomley --- drivers/scsi/aic7xxx/aic79xx_osm.c | 96 +++++++++++++++++++--- drivers/scsi/aic7xxx/aic79xx_proc.c | 45 ++++++++++- drivers/scsi/aic7xxx/aic7xxx_osm.c | 89 ++++++++++++++++++-- drivers/scsi/aic7xxx/aic7xxx_proc.c | 45 ++++++++++- drivers/scsi/aic7xxx/aiclib.c | 121 ---------------------------- drivers/scsi/aic7xxx/aiclib.h | 22 ----- 6 files changed, 253 insertions(+), 165 deletions(-) diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c index 3feb739cd554..6b6d4e287793 100644 --- a/drivers/scsi/aic7xxx/aic79xx_osm.c +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c @@ -48,12 +48,6 @@ static struct scsi_transport_template *ahd_linux_transport_template = NULL; -/* - * Include aiclib.c as part of our - * "module dependencies are hard" work around. - */ -#include "aiclib.c" - #include /* __setup */ #include /* For fetching system memory size */ #include /* For block_size() */ @@ -372,8 +366,6 @@ static int ahd_linux_run_command(struct ahd_softc*, struct ahd_linux_device *, struct scsi_cmnd *); static void ahd_linux_setup_tag_info_global(char *p); -static aic_option_callback_t ahd_linux_setup_tag_info; -static aic_option_callback_t ahd_linux_setup_iocell_info; static int aic79xx_setup(char *c); static int ahd_linux_unit; @@ -907,6 +899,86 @@ ahd_linux_setup_tag_info(u_long arg, int instance, int targ, int32_t value) } } +static char * +ahd_parse_brace_option(char *opt_name, char *opt_arg, char *end, int depth, + void (*callback)(u_long, int, int, int32_t), + u_long callback_arg) +{ + char *tok_end; + char *tok_end2; + int i; + int instance; + int targ; + int done; + char tok_list[] = {'.', ',', '{', '}', '\0'}; + + /* All options use a ':' name/arg separator */ + if (*opt_arg != ':') + return (opt_arg); + opt_arg++; + instance = -1; + targ = -1; + done = FALSE; + /* + * Restore separator that may be in + * the middle of our option argument. + */ + tok_end = strchr(opt_arg, '\0'); + if (tok_end < end) + *tok_end = ','; + while (!done) { + switch (*opt_arg) { + case '{': + if (instance == -1) { + instance = 0; + } else { + if (depth > 1) { + if (targ == -1) + targ = 0; + } else { + printf("Malformed Option %s\n", + opt_name); + done = TRUE; + } + } + opt_arg++; + break; + case '}': + if (targ != -1) + targ = -1; + else if (instance != -1) + instance = -1; + opt_arg++; + break; + case ',': + case '.': + if (instance == -1) + done = TRUE; + else if (targ >= 0) + targ++; + else if (instance >= 0) + instance++; + opt_arg++; + break; + case '\0': + done = TRUE; + break; + default: + tok_end = end; + for (i = 0; tok_list[i]; i++) { + tok_end2 = strchr(opt_arg, tok_list[i]); + if ((tok_end2) && (tok_end2 < tok_end)) + tok_end = tok_end2; + } + callback(callback_arg, instance, targ, + simple_strtol(opt_arg, NULL, 0)); + opt_arg = tok_end; + break; + } + } + return (opt_arg); +} + /* * Handle Linux boot parameters. This routine allows for assigning a value * to a parameter with a ':' between the parameter and the value. @@ -964,18 +1036,18 @@ aic79xx_setup(char *s) if (strncmp(p, "global_tag_depth", n) == 0) { ahd_linux_setup_tag_info_global(p + n); } else if (strncmp(p, "tag_info", n) == 0) { - s = aic_parse_brace_option("tag_info", p + n, end, + s = ahd_parse_brace_option("tag_info", p + n, end, 2, ahd_linux_setup_tag_info, 0); } else if (strncmp(p, "slewrate", n) == 0) { - s = aic_parse_brace_option("slewrate", + s = ahd_parse_brace_option("slewrate", p + n, end, 1, ahd_linux_setup_iocell_info, AIC79XX_SLEWRATE_INDEX); } else if (strncmp(p, "precomp", n) == 0) { - s = aic_parse_brace_option("precomp", + s = ahd_parse_brace_option("precomp", p + n, end, 1, ahd_linux_setup_iocell_info, AIC79XX_PRECOMP_INDEX); } else if (strncmp(p, "amplitude", n) == 0) { - s = aic_parse_brace_option("amplitude", + s = ahd_parse_brace_option("amplitude", p + n, end, 1, ahd_linux_setup_iocell_info, AIC79XX_AMPLITUDE_INDEX); } else if (p[n] == ':') { diff --git a/drivers/scsi/aic7xxx/aic79xx_proc.c b/drivers/scsi/aic7xxx/aic79xx_proc.c index 32be1f55998c..39a27840fce6 100644 --- a/drivers/scsi/aic7xxx/aic79xx_proc.c +++ b/drivers/scsi/aic7xxx/aic79xx_proc.c @@ -53,6 +53,49 @@ static void ahd_dump_device_state(struct info_str *info, static int ahd_proc_write_seeprom(struct ahd_softc *ahd, char *buffer, int length); +/* + * Table of syncrates that don't follow the "divisible by 4" + * rule. This table will be expanded in future SCSI specs. + */ +static struct { + u_int period_factor; + u_int period; /* in 100ths of ns */ +} scsi_syncrates[] = { + { 0x08, 625 }, /* FAST-160 */ + { 0x09, 1250 }, /* FAST-80 */ + { 0x0a, 2500 }, /* FAST-40 40MHz */ + { 0x0b, 3030 }, /* FAST-40 33MHz */ + { 0x0c, 5000 } /* FAST-20 */ +}; + +/* + * Return the frequency in kHz corresponding to the given + * sync period factor. + */ +static u_int +ahd_calc_syncsrate(u_int period_factor) +{ + int i; + int num_syncrates; + + num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]); + /* See if the period is in the "exception" table */ + for (i = 0; i < num_syncrates; i++) { + + if (period_factor == scsi_syncrates[i].period_factor) { + /* Period in kHz */ + return (100000000 / scsi_syncrates[i].period); + } + } + + /* + * Wasn't in the table, so use the standard + * 4 times conversion. + */ + return (10000000 / (period_factor * 4 * 10)); +} + + static void copy_mem_info(struct info_str *info, char *data, int len) { @@ -109,7 +152,7 @@ ahd_format_transinfo(struct info_str *info, struct ahd_transinfo *tinfo) speed = 3300; freq = 0; if (tinfo->offset != 0) { - freq = aic_calc_syncsrate(tinfo->period); + freq = ahd_calc_syncsrate(tinfo->period); speed = freq; } speed *= (0x01 << tinfo->width); diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index 22434849de48..4096d523d08d 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -125,12 +125,6 @@ static struct scsi_transport_template *ahc_linux_transport_template = NULL; -/* - * Include aiclib.c as part of our - * "module dependencies are hard" work around. - */ -#include "aiclib.c" - #include /* __setup */ #include /* For fetching system memory size */ #include /* For block_size() */ @@ -391,7 +385,6 @@ static int ahc_linux_run_command(struct ahc_softc*, struct ahc_linux_device *, struct scsi_cmnd *); static void ahc_linux_setup_tag_info_global(char *p); -static aic_option_callback_t ahc_linux_setup_tag_info; static int aic7xxx_setup(char *s); static int ahc_linux_unit; @@ -920,6 +913,86 @@ ahc_linux_setup_tag_info(u_long arg, int instance, int targ, int32_t value) } } +static char * +ahc_parse_brace_option(char *opt_name, char *opt_arg, char *end, int depth, + void (*callback)(u_long, int, int, int32_t), + u_long callback_arg) +{ + char *tok_end; + char *tok_end2; + int i; + int instance; + int targ; + int done; + char tok_list[] = {'.', ',', '{', '}', '\0'}; + + /* All options use a ':' name/arg separator */ + if (*opt_arg != ':') + return (opt_arg); + opt_arg++; + instance = -1; + targ = -1; + done = FALSE; + /* + * Restore separator that may be in + * the middle of our option argument. + */ + tok_end = strchr(opt_arg, '\0'); + if (tok_end < end) + *tok_end = ','; + while (!done) { + switch (*opt_arg) { + case '{': + if (instance == -1) { + instance = 0; + } else { + if (depth > 1) { + if (targ == -1) + targ = 0; + } else { + printf("Malformed Option %s\n", + opt_name); + done = TRUE; + } + } + opt_arg++; + break; + case '}': + if (targ != -1) + targ = -1; + else if (instance != -1) + instance = -1; + opt_arg++; + break; + case ',': + case '.': + if (instance == -1) + done = TRUE; + else if (targ >= 0) + targ++; + else if (instance >= 0) + instance++; + opt_arg++; + break; + case '\0': + done = TRUE; + break; + default: + tok_end = end; + for (i = 0; tok_list[i]; i++) { + tok_end2 = strchr(opt_arg, tok_list[i]); + if ((tok_end2) && (tok_end2 < tok_end)) + tok_end = tok_end2; + } + callback(callback_arg, instance, targ, + simple_strtol(opt_arg, NULL, 0)); + opt_arg = tok_end; + break; + } + } + return (opt_arg); +} + /* * Handle Linux boot parameters. This routine allows for assigning a value * to a parameter with a ':' between the parameter and the value. @@ -974,7 +1047,7 @@ aic7xxx_setup(char *s) if (strncmp(p, "global_tag_depth", n) == 0) { ahc_linux_setup_tag_info_global(p + n); } else if (strncmp(p, "tag_info", n) == 0) { - s = aic_parse_brace_option("tag_info", p + n, end, + s = ahc_parse_brace_option("tag_info", p + n, end, 2, ahc_linux_setup_tag_info, 0); } else if (p[n] == ':') { *(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0); diff --git a/drivers/scsi/aic7xxx/aic7xxx_proc.c b/drivers/scsi/aic7xxx/aic7xxx_proc.c index 3802c91f0b07..04a3506cf340 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_proc.c +++ b/drivers/scsi/aic7xxx/aic7xxx_proc.c @@ -54,6 +54,49 @@ static void ahc_dump_device_state(struct info_str *info, static int ahc_proc_write_seeprom(struct ahc_softc *ahc, char *buffer, int length); +/* + * Table of syncrates that don't follow the "divisible by 4" + * rule. This table will be expanded in future SCSI specs. + */ +static struct { + u_int period_factor; + u_int period; /* in 100ths of ns */ +} scsi_syncrates[] = { + { 0x08, 625 }, /* FAST-160 */ + { 0x09, 1250 }, /* FAST-80 */ + { 0x0a, 2500 }, /* FAST-40 40MHz */ + { 0x0b, 3030 }, /* FAST-40 33MHz */ + { 0x0c, 5000 } /* FAST-20 */ +}; + +/* + * Return the frequency in kHz corresponding to the given + * sync period factor. + */ +static u_int +ahc_calc_syncsrate(u_int period_factor) +{ + int i; + int num_syncrates; + + num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]); + /* See if the period is in the "exception" table */ + for (i = 0; i < num_syncrates; i++) { + + if (period_factor == scsi_syncrates[i].period_factor) { + /* Period in kHz */ + return (100000000 / scsi_syncrates[i].period); + } + } + + /* + * Wasn't in the table, so use the standard + * 4 times conversion. + */ + return (10000000 / (period_factor * 4 * 10)); +} + + static void copy_mem_info(struct info_str *info, char *data, int len) { @@ -106,7 +149,7 @@ ahc_format_transinfo(struct info_str *info, struct ahc_transinfo *tinfo) speed = 3300; freq = 0; if (tinfo->offset != 0) { - freq = aic_calc_syncsrate(tinfo->period); + freq = ahc_calc_syncsrate(tinfo->period); speed = freq; } speed *= (0x01 << tinfo->width); diff --git a/drivers/scsi/aic7xxx/aiclib.c b/drivers/scsi/aic7xxx/aiclib.c index 4d44a9211185..828ae3d9a510 100644 --- a/drivers/scsi/aic7xxx/aiclib.c +++ b/drivers/scsi/aic7xxx/aiclib.c @@ -32,124 +32,3 @@ #include "aiclib.h" - -/* - * Table of syncrates that don't follow the "divisible by 4" - * rule. This table will be expanded in future SCSI specs. - */ -static struct { - u_int period_factor; - u_int period; /* in 100ths of ns */ -} scsi_syncrates[] = { - { 0x08, 625 }, /* FAST-160 */ - { 0x09, 1250 }, /* FAST-80 */ - { 0x0a, 2500 }, /* FAST-40 40MHz */ - { 0x0b, 3030 }, /* FAST-40 33MHz */ - { 0x0c, 5000 } /* FAST-20 */ -}; - -/* - * Return the frequency in kHz corresponding to the given - * sync period factor. - */ -u_int -aic_calc_syncsrate(u_int period_factor) -{ - int i; - int num_syncrates; - - num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]); - /* See if the period is in the "exception" table */ - for (i = 0; i < num_syncrates; i++) { - - if (period_factor == scsi_syncrates[i].period_factor) { - /* Period in kHz */ - return (100000000 / scsi_syncrates[i].period); - } - } - - /* - * Wasn't in the table, so use the standard - * 4 times conversion. - */ - return (10000000 / (period_factor * 4 * 10)); -} - -char * -aic_parse_brace_option(char *opt_name, char *opt_arg, char *end, int depth, - aic_option_callback_t *callback, u_long callback_arg) -{ - char *tok_end; - char *tok_end2; - int i; - int instance; - int targ; - int done; - char tok_list[] = {'.', ',', '{', '}', '\0'}; - - /* All options use a ':' name/arg separator */ - if (*opt_arg != ':') - return (opt_arg); - opt_arg++; - instance = -1; - targ = -1; - done = FALSE; - /* - * Restore separator that may be in - * the middle of our option argument. - */ - tok_end = strchr(opt_arg, '\0'); - if (tok_end < end) - *tok_end = ','; - while (!done) { - switch (*opt_arg) { - case '{': - if (instance == -1) { - instance = 0; - } else { - if (depth > 1) { - if (targ == -1) - targ = 0; - } else { - printf("Malformed Option %s\n", - opt_name); - done = TRUE; - } - } - opt_arg++; - break; - case '}': - if (targ != -1) - targ = -1; - else if (instance != -1) - instance = -1; - opt_arg++; - break; - case ',': - case '.': - if (instance == -1) - done = TRUE; - else if (targ >= 0) - targ++; - else if (instance >= 0) - instance++; - opt_arg++; - break; - case '\0': - done = TRUE; - break; - default: - tok_end = end; - for (i = 0; tok_list[i]; i++) { - tok_end2 = strchr(opt_arg, tok_list[i]); - if ((tok_end2) && (tok_end2 < tok_end)) - tok_end = tok_end2; - } - callback(callback_arg, instance, targ, - simple_strtol(opt_arg, NULL, 0)); - opt_arg = tok_end; - break; - } - } - return (opt_arg); -} diff --git a/drivers/scsi/aic7xxx/aiclib.h b/drivers/scsi/aic7xxx/aiclib.h index e7d94cbaf2a8..3bfbf0fe1ec2 100644 --- a/drivers/scsi/aic7xxx/aiclib.h +++ b/drivers/scsi/aic7xxx/aiclib.h @@ -141,28 +141,6 @@ aic_sector_div(sector_t capacity, int heads, int sectors) return (int)capacity; } -/**************************** Module Library Hack *****************************/ -/* - * What we'd like to do is have a single "scsi library" module that both the - * aic7xxx and aic79xx drivers could load and depend on. A cursory examination - * of implementing module dependencies in Linux (handling the install and - * initrd cases) does not look promissing. For now, we just duplicate this - * code in both drivers using a simple symbol renaming scheme that hides this - * hack from the drivers. - */ -#define AIC_LIB_ENTRY_CONCAT(x, prefix) prefix ## x -#define AIC_LIB_ENTRY_EXPAND(x, prefix) AIC_LIB_ENTRY_CONCAT(x, prefix) -#define AIC_LIB_ENTRY(x) AIC_LIB_ENTRY_EXPAND(x, AIC_LIB_PREFIX) - -#define aic_calc_syncsrate AIC_LIB_ENTRY(_calc_syncrate) - -u_int aic_calc_syncsrate(u_int /*period_factor*/); - -typedef void aic_option_callback_t(u_long, int, int, int32_t); -char * aic_parse_brace_option(char *opt_name, char *opt_arg, - char *end, int depth, - aic_option_callback_t *, u_long); - static __inline uint32_t scsi_4btoul(uint8_t *bytes) { From 69218ee5186aded6c78e12e083e073d000ff2e9b Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 18 Aug 2005 16:26:15 +0200 Subject: [PATCH 089/114] [SCSI] fusion: extended config header support Acked by: Moore, Eric Dean Signed-off-by: James Bottomley --- drivers/message/fusion/mptbase.c | 90 +++++++++++++++++++++---------- drivers/message/fusion/mptbase.h | 5 +- drivers/message/fusion/mptctl.c | 12 ++--- drivers/message/fusion/mptscsih.c | 18 +++---- 4 files changed, 81 insertions(+), 44 deletions(-) diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index ffbe6f4720e1..284202766804 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -491,10 +491,21 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply) pCfg->status = status; if (status == MPI_IOCSTATUS_SUCCESS) { - pCfg->hdr->PageVersion = pReply->Header.PageVersion; - pCfg->hdr->PageLength = pReply->Header.PageLength; - pCfg->hdr->PageNumber = pReply->Header.PageNumber; - pCfg->hdr->PageType = pReply->Header.PageType; + if ((pReply->Header.PageType & + MPI_CONFIG_PAGETYPE_MASK) == + MPI_CONFIG_PAGETYPE_EXTENDED) { + pCfg->cfghdr.ehdr->ExtPageLength = + le16_to_cpu(pReply->ExtPageLength); + pCfg->cfghdr.ehdr->ExtPageType = + pReply->ExtPageType; + } + pCfg->cfghdr.hdr->PageVersion = pReply->Header.PageVersion; + + /* If this is a regular header, save PageLength. */ + /* LMP Do this better so not using a reserved field! */ + pCfg->cfghdr.hdr->PageLength = pReply->Header.PageLength; + pCfg->cfghdr.hdr->PageNumber = pReply->Header.PageNumber; + pCfg->cfghdr.hdr->PageType = pReply->Header.PageType; } } @@ -3819,7 +3830,7 @@ GetLanConfigPages(MPT_ADAPTER *ioc) hdr.PageLength = 0; hdr.PageNumber = 0; hdr.PageType = MPI_CONFIG_PAGETYPE_LAN; - cfg.hdr = &hdr; + cfg.cfghdr.hdr = &hdr; cfg.physAddr = -1; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; cfg.dir = 0; @@ -3863,7 +3874,7 @@ GetLanConfigPages(MPT_ADAPTER *ioc) hdr.PageLength = 0; hdr.PageNumber = 1; hdr.PageType = MPI_CONFIG_PAGETYPE_LAN; - cfg.hdr = &hdr; + cfg.cfghdr.hdr = &hdr; cfg.physAddr = -1; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; cfg.dir = 0; @@ -3930,7 +3941,7 @@ GetFcPortPage0(MPT_ADAPTER *ioc, int portnum) hdr.PageLength = 0; hdr.PageNumber = 0; hdr.PageType = MPI_CONFIG_PAGETYPE_FC_PORT; - cfg.hdr = &hdr; + cfg.cfghdr.hdr = &hdr; cfg.physAddr = -1; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; cfg.dir = 0; @@ -4012,7 +4023,7 @@ GetIoUnitPage2(MPT_ADAPTER *ioc) hdr.PageLength = 0; hdr.PageNumber = 2; hdr.PageType = MPI_CONFIG_PAGETYPE_IO_UNIT; - cfg.hdr = &hdr; + cfg.cfghdr.hdr = &hdr; cfg.physAddr = -1; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; cfg.dir = 0; @@ -4102,7 +4113,7 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum) header.PageLength = 0; header.PageNumber = 0; header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT; - cfg.hdr = &header; + cfg.cfghdr.hdr = &header; cfg.physAddr = -1; cfg.pageAddr = portnum; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; @@ -4168,7 +4179,7 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum) header.PageLength = 0; header.PageNumber = 2; header.PageType = MPI_CONFIG_PAGETYPE_SCSI_PORT; - cfg.hdr = &header; + cfg.cfghdr.hdr = &header; cfg.physAddr = -1; cfg.pageAddr = portnum; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; @@ -4236,7 +4247,7 @@ mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum) header.PageLength = 0; header.PageNumber = 1; header.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE; - cfg.hdr = &header; + cfg.cfghdr.hdr = &header; cfg.physAddr = -1; cfg.pageAddr = portnum; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; @@ -4245,8 +4256,8 @@ mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum) if (mpt_config(ioc, &cfg) != 0) return -EFAULT; - ioc->spi_data.sdp1version = cfg.hdr->PageVersion; - ioc->spi_data.sdp1length = cfg.hdr->PageLength; + ioc->spi_data.sdp1version = cfg.cfghdr.hdr->PageVersion; + ioc->spi_data.sdp1length = cfg.cfghdr.hdr->PageLength; header.PageVersion = 0; header.PageLength = 0; @@ -4255,8 +4266,8 @@ mpt_readScsiDevicePageHeaders(MPT_ADAPTER *ioc, int portnum) if (mpt_config(ioc, &cfg) != 0) return -EFAULT; - ioc->spi_data.sdp0version = cfg.hdr->PageVersion; - ioc->spi_data.sdp0length = cfg.hdr->PageLength; + ioc->spi_data.sdp0version = cfg.cfghdr.hdr->PageVersion; + ioc->spi_data.sdp0length = cfg.cfghdr.hdr->PageLength; dcprintk((MYIOC_s_INFO_FMT "Headers: 0: version %d length %d\n", ioc->name, ioc->spi_data.sdp0version, ioc->spi_data.sdp0length)); @@ -4298,7 +4309,7 @@ mpt_findImVolumes(MPT_ADAPTER *ioc) header.PageLength = 0; header.PageNumber = 2; header.PageType = MPI_CONFIG_PAGETYPE_IOC; - cfg.hdr = &header; + cfg.cfghdr.hdr = &header; cfg.physAddr = -1; cfg.pageAddr = 0; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; @@ -4394,7 +4405,7 @@ mpt_read_ioc_pg_3(MPT_ADAPTER *ioc) header.PageLength = 0; header.PageNumber = 3; header.PageType = MPI_CONFIG_PAGETYPE_IOC; - cfg.hdr = &header; + cfg.cfghdr.hdr = &header; cfg.physAddr = -1; cfg.pageAddr = 0; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; @@ -4446,7 +4457,7 @@ mpt_read_ioc_pg_4(MPT_ADAPTER *ioc) header.PageLength = 0; header.PageNumber = 4; header.PageType = MPI_CONFIG_PAGETYPE_IOC; - cfg.hdr = &header; + cfg.cfghdr.hdr = &header; cfg.physAddr = -1; cfg.pageAddr = 0; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; @@ -4498,7 +4509,7 @@ mpt_read_ioc_pg_1(MPT_ADAPTER *ioc) header.PageLength = 0; header.PageNumber = 1; header.PageType = MPI_CONFIG_PAGETYPE_IOC; - cfg.hdr = &header; + cfg.cfghdr.hdr = &header; cfg.physAddr = -1; cfg.pageAddr = 0; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; @@ -4647,10 +4658,11 @@ int mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg) { Config_t *pReq; + ConfigExtendedPageHeader_t *pExtHdr = NULL; MPT_FRAME_HDR *mf; unsigned long flags; int ii, rc; - u32 flagsLength; + int flagsLength; int in_isr; /* Prevent calling wait_event() (below), if caller happens @@ -4675,16 +4687,30 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg) pReq->Reserved = 0; pReq->ChainOffset = 0; pReq->Function = MPI_FUNCTION_CONFIG; + + /* Assume page type is not extended and clear "reserved" fields. */ pReq->ExtPageLength = 0; pReq->ExtPageType = 0; pReq->MsgFlags = 0; + for (ii=0; ii < 8; ii++) pReq->Reserved2[ii] = 0; - pReq->Header.PageVersion = pCfg->hdr->PageVersion; - pReq->Header.PageLength = pCfg->hdr->PageLength; - pReq->Header.PageNumber = pCfg->hdr->PageNumber; - pReq->Header.PageType = (pCfg->hdr->PageType & MPI_CONFIG_PAGETYPE_MASK); + pReq->Header.PageVersion = pCfg->cfghdr.hdr->PageVersion; + pReq->Header.PageLength = pCfg->cfghdr.hdr->PageLength; + pReq->Header.PageNumber = pCfg->cfghdr.hdr->PageNumber; + pReq->Header.PageType = (pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK); + + if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) { + pExtHdr = (ConfigExtendedPageHeader_t *)pCfg->cfghdr.ehdr; + pReq->ExtPageLength = cpu_to_le16(pExtHdr->ExtPageLength); + pReq->ExtPageType = pExtHdr->ExtPageType; + pReq->Header.PageType = MPI_CONFIG_PAGETYPE_EXTENDED; + + /* Page Length must be treated as a reserved field for the extended header. */ + pReq->Header.PageLength = 0; + } + pReq->PageAddress = cpu_to_le32(pCfg->pageAddr); /* Add a SGE to the config request. @@ -4694,13 +4720,21 @@ mpt_config(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg) else flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ; - flagsLength |= pCfg->hdr->PageLength * 4; + if ((pCfg->cfghdr.hdr->PageType & MPI_CONFIG_PAGETYPE_MASK) == MPI_CONFIG_PAGETYPE_EXTENDED) { + flagsLength |= pExtHdr->ExtPageLength * 4; + + dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n", + ioc->name, pReq->ExtPageType, pReq->Header.PageNumber, pReq->Action)); + } + else { + flagsLength |= pCfg->cfghdr.hdr->PageLength * 4; + + dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n", + ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action)); + } mpt_add_sge((char *)&pReq->PageBufferSGE, flagsLength, pCfg->physAddr); - dcprintk((MYIOC_s_INFO_FMT "Sending Config request type %d, page %d and action %d\n", - ioc->name, pReq->Header.PageType, pReq->Header.PageNumber, pReq->Action)); - /* Append pCfg pointer to end of mf */ *((void **) (((u8 *) mf) + (ioc->req_sz - sizeof(void *)))) = (void *) pCfg; diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index 848fb236b175..f4827d923731 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h @@ -915,7 +915,10 @@ struct scsi_cmnd; typedef struct _x_config_parms { struct list_head linkage; /* linked list */ struct timer_list timer; /* timer function for this request */ - ConfigPageHeader_t *hdr; + union { + ConfigExtendedPageHeader_t *ehdr; + ConfigPageHeader_t *hdr; + } cfghdr; dma_addr_t physAddr; int wait_done; /* wait for this request */ u32 pageAddr; /* properly formatted */ diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c index 05ea5944c487..e63a3fd6b706 100644 --- a/drivers/message/fusion/mptctl.c +++ b/drivers/message/fusion/mptctl.c @@ -2324,7 +2324,7 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size) hdr.PageLength = 0; hdr.PageNumber = 0; hdr.PageType = MPI_CONFIG_PAGETYPE_MANUFACTURING; - cfg.hdr = &hdr; + cfg.cfghdr.hdr = &hdr; cfg.physAddr = -1; cfg.pageAddr = 0; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; @@ -2333,7 +2333,7 @@ mptctl_hp_hostinfo(unsigned long arg, unsigned int data_size) strncpy(karg.serial_number, " ", 24); if (mpt_config(ioc, &cfg) == 0) { - if (cfg.hdr->PageLength > 0) { + if (cfg.cfghdr.hdr->PageLength > 0) { /* Issue the second config page request */ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; @@ -2479,7 +2479,7 @@ mptctl_hp_targetinfo(unsigned long arg) hdr.PageNumber = 0; hdr.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE; - cfg.hdr = &hdr; + cfg.cfghdr.hdr = &hdr; cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; cfg.dir = 0; cfg.timeout = 0; @@ -2527,15 +2527,15 @@ mptctl_hp_targetinfo(unsigned long arg) hdr.PageNumber = 3; hdr.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE; - cfg.hdr = &hdr; + cfg.cfghdr.hdr = &hdr; cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER; cfg.dir = 0; cfg.timeout = 0; cfg.physAddr = -1; - if ((mpt_config(ioc, &cfg) == 0) && (cfg.hdr->PageLength > 0)) { + if ((mpt_config(ioc, &cfg) == 0) && (cfg.cfghdr.hdr->PageLength > 0)) { /* Issue the second config page request */ cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; - data_sz = (int) cfg.hdr->PageLength * 4; + data_sz = (int) cfg.cfghdr.hdr->PageLength * 4; pg3_alloc = (SCSIDevicePage3_t *) pci_alloc_consistent( ioc->pcidev, data_sz, &page_dma); if (pg3_alloc) { diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index b9d4f78725b4..b774f45dfde4 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -3955,7 +3955,7 @@ mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, int portnum) header1.PageLength = ioc->spi_data.sdp1length; header1.PageNumber = 1; header1.PageType = MPI_CONFIG_PAGETYPE_SCSI_DEVICE; - cfg.hdr = &header1; + cfg.cfghdr.hdr = &header1; cfg.physAddr = cfg1_dma_addr; cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; cfg.dir = 1; @@ -4353,7 +4353,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) /* Prep cfg structure */ cfg.pageAddr = (bus<<8) | id; - cfg.hdr = NULL; + cfg.cfghdr.hdr = NULL; /* Prep SDP0 header */ @@ -4399,7 +4399,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) pcfg1Data = (SCSIDevicePage1_t *) (pDvBuf + sz); cfg1_dma_addr = dvbuf_dma + sz; - /* Skip this ID? Set cfg.hdr to force config page write + /* Skip this ID? Set cfg.cfghdr.hdr to force config page write */ { ScsiCfgData *pspi_data = &hd->ioc->spi_data; @@ -4417,7 +4417,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) dv.cmd = MPT_SET_MAX; mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data); - cfg.hdr = &header1; + cfg.cfghdr.hdr = &header1; /* Save the final negotiated settings to * SCSI device page 1. @@ -4483,7 +4483,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) dv.cmd = MPT_SET_MIN; mptscsih_dv_parms(hd, &dv, (void *)pcfg1Data); - cfg.hdr = &header1; + cfg.cfghdr.hdr = &header1; cfg.physAddr = cfg1_dma_addr; cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; cfg.dir = 1; @@ -4637,7 +4637,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) u32 sdp0_info; u32 sdp0_nego; - cfg.hdr = &header0; + cfg.cfghdr.hdr = &header0; cfg.physAddr = cfg0_dma_addr; cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT; cfg.dir = 0; @@ -4722,7 +4722,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) * 4) release * 5) update nego parms to target struct */ - cfg.hdr = &header1; + cfg.cfghdr.hdr = &header1; cfg.physAddr = cfg1_dma_addr; cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; cfg.dir = 1; @@ -5121,7 +5121,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) /* Set if cfg1_dma_addr contents is valid */ - if ((cfg.hdr != NULL) && (retcode == 0)){ + if ((cfg.cfghdr.hdr != NULL) && (retcode == 0)){ /* If disk, not U320, disable QAS */ if ((inq0 == 0) && (dv.now.factor > MPT_ULTRA320)) { @@ -5137,7 +5137,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) * skip save of the final negotiated settings to * SCSI device page 1. * - cfg.hdr = &header1; + cfg.cfghdr.hdr = &header1; cfg.physAddr = cfg1_dma_addr; cfg.action = MPI_CONFIG_ACTION_PAGE_WRITE_CURRENT; cfg.dir = 1; From ccf3b7bd26b242b39d54148ea2117295721681d3 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 18 Aug 2005 16:24:26 +0200 Subject: [PATCH 090/114] [SCSI] fusion: update LSI headers Acked by: Moore, Eric Dean Signed-off-by: James Bottomley --- drivers/message/fusion/lsi/mpi.h | 19 +- drivers/message/fusion/lsi/mpi_cnfg.h | 85 +++++++-- drivers/message/fusion/lsi/mpi_history.txt | 67 ++++--- drivers/message/fusion/lsi/mpi_init.h | 203 ++++++++++++++++++++- drivers/message/fusion/lsi/mpi_ioc.h | 11 +- drivers/message/fusion/lsi/mpi_targ.h | 74 +++++++- 6 files changed, 415 insertions(+), 44 deletions(-) diff --git a/drivers/message/fusion/lsi/mpi.h b/drivers/message/fusion/lsi/mpi.h index 9f98334e5076..b61e3d175070 100644 --- a/drivers/message/fusion/lsi/mpi.h +++ b/drivers/message/fusion/lsi/mpi.h @@ -6,7 +6,7 @@ * Title: MPI Message independent structures and definitions * Creation Date: July 27, 2000 * - * mpi.h Version: 01.05.07 + * mpi.h Version: 01.05.08 * * Version History * --------------- @@ -71,6 +71,9 @@ * 03-11-05 01.05.07 Removed function codes for SCSI IO 32 and * TargetAssistExtended requests. * Removed EEDP IOCStatus codes. + * 06-24-05 01.05.08 Added function codes for SCSI IO 32 and + * TargetAssistExtended requests. + * Added EEDP IOCStatus codes. * -------------------------------------------------------------------------- */ @@ -101,7 +104,7 @@ /* Note: The major versions of 0xe0 through 0xff are reserved */ /* versioning for this MPI header set */ -#define MPI_HEADER_VERSION_UNIT (0x09) +#define MPI_HEADER_VERSION_UNIT (0x0A) #define MPI_HEADER_VERSION_DEV (0x00) #define MPI_HEADER_VERSION_UNIT_MASK (0xFF00) #define MPI_HEADER_VERSION_UNIT_SHIFT (8) @@ -292,10 +295,13 @@ #define MPI_FUNCTION_DIAG_BUFFER_POST (0x1D) #define MPI_FUNCTION_DIAG_RELEASE (0x1E) +#define MPI_FUNCTION_SCSI_IO_32 (0x1F) + #define MPI_FUNCTION_LAN_SEND (0x20) #define MPI_FUNCTION_LAN_RECEIVE (0x21) #define MPI_FUNCTION_LAN_RESET (0x22) +#define MPI_FUNCTION_TARGET_ASSIST_EXTENDED (0x23) #define MPI_FUNCTION_TARGET_CMD_BUF_BASE_POST (0x24) #define MPI_FUNCTION_TARGET_CMD_BUF_LIST_POST (0x25) @@ -680,6 +686,15 @@ typedef struct _MSG_DEFAULT_REPLY #define MPI_IOCSTATUS_SCSI_IOC_TERMINATED (0x004B) #define MPI_IOCSTATUS_SCSI_EXT_TERMINATED (0x004C) +/****************************************************************************/ +/* For use by SCSI Initiator and SCSI Target end-to-end data protection */ +/****************************************************************************/ + +#define MPI_IOCSTATUS_EEDP_GUARD_ERROR (0x004D) +#define MPI_IOCSTATUS_EEDP_REF_TAG_ERROR (0x004E) +#define MPI_IOCSTATUS_EEDP_APP_TAG_ERROR (0x004F) + + /****************************************************************************/ /* SCSI Target values */ /****************************************************************************/ diff --git a/drivers/message/fusion/lsi/mpi_cnfg.h b/drivers/message/fusion/lsi/mpi_cnfg.h index 15b12b06799d..d8339896f734 100644 --- a/drivers/message/fusion/lsi/mpi_cnfg.h +++ b/drivers/message/fusion/lsi/mpi_cnfg.h @@ -6,7 +6,7 @@ * Title: MPI Config message, structures, and Pages * Creation Date: July 27, 2000 * - * mpi_cnfg.h Version: 01.05.08 + * mpi_cnfg.h Version: 01.05.09 * * Version History * --------------- @@ -232,6 +232,23 @@ * New physical mapping mode in SAS IO Unit Page 2. * Added CONFIG_PAGE_SAS_ENCLOSURE_0. * Added Slot and Enclosure fields to SAS Device Page 0. + * 06-24-05 01.05.09 Added EEDP defines to IOC Page 1. + * Added more RAID type defines to IOC Page 2. + * Added Port Enable Delay settings to BIOS Page 1. + * Added Bad Block Table Full define to RAID Volume Page 0. + * Added Previous State defines to RAID Physical Disk + * Page 0. + * Added Max Sata Targets define for DiscoveryStatus field + * of SAS IO Unit Page 0. + * Added Device Self Test to Control Flags of SAS IO Unit + * Page 1. + * Added Direct Attach Starting Slot Number define for SAS + * IO Unit Page 2. + * Added new fields in SAS Device Page 2 for enclosure + * mapping. + * Added OwnerDevHandle and Flags field to SAS PHY Page 0. + * Added IOC GPIO Flags define to SAS Enclosure Page 0. + * Fixed the value for MPI_SAS_IOUNIT1_CONTROL_DEV_SATA_SUPPORT. * -------------------------------------------------------------------------- */ @@ -477,6 +494,7 @@ typedef struct _MSG_CONFIG_REPLY #define MPI_MANUFACTPAGE_DEVICEID_FC929X (0x0626) #define MPI_MANUFACTPAGE_DEVICEID_FC939X (0x0642) #define MPI_MANUFACTPAGE_DEVICEID_FC949X (0x0640) +#define MPI_MANUFACTPAGE_DEVICEID_FC949ES (0x0646) /* SCSI */ #define MPI_MANUFACTPAGE_DEVID_53C1030 (0x0030) #define MPI_MANUFACTPAGE_DEVID_53C1030ZC (0x0031) @@ -769,9 +787,13 @@ typedef struct _CONFIG_PAGE_IOC_1 } CONFIG_PAGE_IOC_1, MPI_POINTER PTR_CONFIG_PAGE_IOC_1, IOCPage1_t, MPI_POINTER pIOCPage1_t; -#define MPI_IOCPAGE1_PAGEVERSION (0x02) +#define MPI_IOCPAGE1_PAGEVERSION (0x03) /* defines for the Flags field */ +#define MPI_IOCPAGE1_EEDP_MODE_MASK (0x07000000) +#define MPI_IOCPAGE1_EEDP_MODE_OFF (0x00000000) +#define MPI_IOCPAGE1_EEDP_MODE_T10 (0x01000000) +#define MPI_IOCPAGE1_EEDP_MODE_LSI_1 (0x02000000) #define MPI_IOCPAGE1_INITIATOR_CONTEXT_REPLY_DISABLE (0x00000010) #define MPI_IOCPAGE1_REPLY_COALESCING (0x00000001) @@ -795,6 +817,11 @@ typedef struct _CONFIG_PAGE_IOC_2_RAID_VOL #define MPI_RAID_VOL_TYPE_IS (0x00) #define MPI_RAID_VOL_TYPE_IME (0x01) #define MPI_RAID_VOL_TYPE_IM (0x02) +#define MPI_RAID_VOL_TYPE_RAID_5 (0x03) +#define MPI_RAID_VOL_TYPE_RAID_6 (0x04) +#define MPI_RAID_VOL_TYPE_RAID_10 (0x05) +#define MPI_RAID_VOL_TYPE_RAID_50 (0x06) +#define MPI_RAID_VOL_TYPE_UNKNOWN (0xFF) /* IOC Page 2 Volume Flags values */ @@ -820,13 +847,17 @@ typedef struct _CONFIG_PAGE_IOC_2 } CONFIG_PAGE_IOC_2, MPI_POINTER PTR_CONFIG_PAGE_IOC_2, IOCPage2_t, MPI_POINTER pIOCPage2_t; -#define MPI_IOCPAGE2_PAGEVERSION (0x02) +#define MPI_IOCPAGE2_PAGEVERSION (0x03) /* IOC Page 2 Capabilities flags */ #define MPI_IOCPAGE2_CAP_FLAGS_IS_SUPPORT (0x00000001) #define MPI_IOCPAGE2_CAP_FLAGS_IME_SUPPORT (0x00000002) #define MPI_IOCPAGE2_CAP_FLAGS_IM_SUPPORT (0x00000004) +#define MPI_IOCPAGE2_CAP_FLAGS_RAID_5_SUPPORT (0x00000008) +#define MPI_IOCPAGE2_CAP_FLAGS_RAID_6_SUPPORT (0x00000010) +#define MPI_IOCPAGE2_CAP_FLAGS_RAID_10_SUPPORT (0x00000020) +#define MPI_IOCPAGE2_CAP_FLAGS_RAID_50_SUPPORT (0x00000040) #define MPI_IOCPAGE2_CAP_FLAGS_SES_SUPPORT (0x20000000) #define MPI_IOCPAGE2_CAP_FLAGS_SAFTE_SUPPORT (0x40000000) #define MPI_IOCPAGE2_CAP_FLAGS_CROSS_CHANNEL_SUPPORT (0x80000000) @@ -945,7 +976,7 @@ typedef struct _CONFIG_PAGE_BIOS_1 } CONFIG_PAGE_BIOS_1, MPI_POINTER PTR_CONFIG_PAGE_BIOS_1, BIOSPage1_t, MPI_POINTER pBIOSPage1_t; -#define MPI_BIOSPAGE1_PAGEVERSION (0x01) +#define MPI_BIOSPAGE1_PAGEVERSION (0x02) /* values for the BiosOptions field */ #define MPI_BIOSPAGE1_OPTIONS_SPI_ENABLE (0x00000400) @@ -954,6 +985,8 @@ typedef struct _CONFIG_PAGE_BIOS_1 #define MPI_BIOSPAGE1_OPTIONS_DISABLE_BIOS (0x00000001) /* values for the IOCSettings field */ +#define MPI_BIOSPAGE1_IOCSET_MASK_PORT_ENABLE_DELAY (0x00F00000) +#define MPI_BIOSPAGE1_IOCSET_SHIFT_PORT_ENABLE_DELAY (20) #define MPI_BIOSPAGE1_IOCSET_MASK_BOOT_PREFERENCE (0x00030000) #define MPI_BIOSPAGE1_IOCSET_ENCLOSURE_SLOT_BOOT (0x00000000) #define MPI_BIOSPAGE1_IOCSET_SAS_ADDRESS_BOOT (0x00010000) @@ -1167,6 +1200,7 @@ typedef struct _CONFIG_PAGE_BIOS_2 #define MPI_BIOSPAGE2_FORM_PCI_SLOT_NUMBER (0x03) #define MPI_BIOSPAGE2_FORM_FC_WWN (0x04) #define MPI_BIOSPAGE2_FORM_SAS_WWN (0x05) +#define MPI_BIOSPAGE2_FORM_ENCLOSURE_SLOT (0x06) /**************************************************************************** @@ -1957,11 +1991,11 @@ typedef struct _RAID_VOL0_STATUS RaidVol0Status_t, MPI_POINTER pRaidVol0Status_t; /* RAID Volume Page 0 VolumeStatus defines */ - #define MPI_RAIDVOL0_STATUS_FLAG_ENABLED (0x01) #define MPI_RAIDVOL0_STATUS_FLAG_QUIESCED (0x02) #define MPI_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS (0x04) #define MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE (0x08) +#define MPI_RAIDVOL0_STATUS_FLAG_BAD_BLOCK_TABLE_FULL (0x10) #define MPI_RAIDVOL0_STATUS_STATE_OPTIMAL (0x00) #define MPI_RAIDVOL0_STATUS_STATE_DEGRADED (0x01) @@ -2025,7 +2059,7 @@ typedef struct _CONFIG_PAGE_RAID_VOL_0 } CONFIG_PAGE_RAID_VOL_0, MPI_POINTER PTR_CONFIG_PAGE_RAID_VOL_0, RaidVolumePage0_t, MPI_POINTER pRaidVolumePage0_t; -#define MPI_RAIDVOLPAGE0_PAGEVERSION (0x04) +#define MPI_RAIDVOLPAGE0_PAGEVERSION (0x05) /* values for RAID Volume Page 0 InactiveStatus field */ #define MPI_RAIDVOLPAGE0_UNKNOWN_INACTIVE (0x00) @@ -2104,6 +2138,8 @@ typedef struct _RAID_PHYS_DISK0_STATUS #define MPI_PHYSDISK0_STATUS_FLAG_OUT_OF_SYNC (0x01) #define MPI_PHYSDISK0_STATUS_FLAG_QUIESCED (0x02) #define MPI_PHYSDISK0_STATUS_FLAG_INACTIVE_VOLUME (0x04) +#define MPI_PHYSDISK0_STATUS_FLAG_OPTIMAL_PREVIOUS (0x00) +#define MPI_PHYSDISK0_STATUS_FLAG_NOT_OPTIMAL_PREVIOUS (0x08) #define MPI_PHYSDISK0_STATUS_ONLINE (0x00) #define MPI_PHYSDISK0_STATUS_MISSING (0x01) @@ -2132,7 +2168,7 @@ typedef struct _CONFIG_PAGE_RAID_PHYS_DISK_0 } CONFIG_PAGE_RAID_PHYS_DISK_0, MPI_POINTER PTR_CONFIG_PAGE_RAID_PHYS_DISK_0, RaidPhysDiskPage0_t, MPI_POINTER pRaidPhysDiskPage0_t; -#define MPI_RAIDPHYSDISKPAGE0_PAGEVERSION (0x01) +#define MPI_RAIDPHYSDISKPAGE0_PAGEVERSION (0x02) typedef struct _RAID_PHYS_DISK1_PATH @@ -2263,7 +2299,7 @@ typedef struct _CONFIG_PAGE_SAS_IO_UNIT_0 } CONFIG_PAGE_SAS_IO_UNIT_0, MPI_POINTER PTR_CONFIG_PAGE_SAS_IO_UNIT_0, SasIOUnitPage0_t, MPI_POINTER pSasIOUnitPage0_t; -#define MPI_SASIOUNITPAGE0_PAGEVERSION (0x02) +#define MPI_SASIOUNITPAGE0_PAGEVERSION (0x03) /* values for SAS IO Unit Page 0 PortFlags */ #define MPI_SAS_IOUNIT0_PORT_FLAGS_DISCOVERY_IN_PROGRESS (0x08) @@ -2299,6 +2335,7 @@ typedef struct _CONFIG_PAGE_SAS_IO_UNIT_0 #define MPI_SAS_IOUNIT0_DS_SUBTRACTIVE_LINK (0x00000200) #define MPI_SAS_IOUNIT0_DS_TABLE_LINK (0x00000400) #define MPI_SAS_IOUNIT0_DS_UNSUPPORTED_DEVICE (0x00000800) +#define MPI_SAS_IOUNIT0_DS_MAX_SATA_TARGETS (0x00001000) typedef struct _MPI_SAS_IO_UNIT1_PHY_DATA @@ -2336,6 +2373,7 @@ typedef struct _CONFIG_PAGE_SAS_IO_UNIT_1 #define MPI_SASIOUNITPAGE1_PAGEVERSION (0x04) /* values for SAS IO Unit Page 1 ControlFlags */ +#define MPI_SAS_IOUNIT1_CONTROL_DEVICE_SELF_TEST (0x8000) #define MPI_SAS_IOUNIT1_CONTROL_SATA_3_0_MAX (0x4000) #define MPI_SAS_IOUNIT1_CONTROL_SATA_1_5_MAX (0x2000) #define MPI_SAS_IOUNIT1_CONTROL_SATA_SW_PRESERVE (0x1000) @@ -2345,9 +2383,8 @@ typedef struct _CONFIG_PAGE_SAS_IO_UNIT_1 #define MPI_SAS_IOUNIT1_CONTROL_SHIFT_DEV_SUPPORT (9) #define MPI_SAS_IOUNIT1_CONTROL_DEV_SUPPORT_BOTH (0x00) #define MPI_SAS_IOUNIT1_CONTROL_DEV_SAS_SUPPORT (0x01) -#define MPI_SAS_IOUNIT1_CONTROL_DEV_SATA_SUPPORT (0x10) +#define MPI_SAS_IOUNIT1_CONTROL_DEV_SATA_SUPPORT (0x02) -#define MPI_SAS_IOUNIT1_CONTROL_AUTO_PORT_SAME_SAS_ADDR (0x0100) #define MPI_SAS_IOUNIT1_CONTROL_SATA_48BIT_LBA_REQUIRED (0x0080) #define MPI_SAS_IOUNIT1_CONTROL_SATA_SMART_REQUIRED (0x0040) #define MPI_SAS_IOUNIT1_CONTROL_SATA_NCQ_REQUIRED (0x0020) @@ -2390,7 +2427,7 @@ typedef struct _CONFIG_PAGE_SAS_IO_UNIT_2 } CONFIG_PAGE_SAS_IO_UNIT_2, MPI_POINTER PTR_CONFIG_PAGE_SAS_IO_UNIT_2, SasIOUnitPage2_t, MPI_POINTER pSasIOUnitPage2_t; -#define MPI_SASIOUNITPAGE2_PAGEVERSION (0x03) +#define MPI_SASIOUNITPAGE2_PAGEVERSION (0x04) /* values for SAS IO Unit Page 2 Status field */ #define MPI_SAS_IOUNIT2_STATUS_DISABLED_PERSISTENT_MAPPINGS (0x02) @@ -2406,6 +2443,7 @@ typedef struct _CONFIG_PAGE_SAS_IO_UNIT_2 #define MPI_SAS_IOUNIT2_FLAGS_ENCLOSURE_SLOT_PHYS_MAP (0x02) #define MPI_SAS_IOUNIT2_FLAGS_RESERVE_ID_0_FOR_BOOT (0x10) +#define MPI_SAS_IOUNIT2_FLAGS_DA_STARTING_SLOT (0x20) typedef struct _CONFIG_PAGE_SAS_IO_UNIT_3 @@ -2584,11 +2622,19 @@ typedef struct _CONFIG_PAGE_SAS_DEVICE_2 { CONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ U64 PhysicalIdentifier; /* 08h */ - U32 Reserved1; /* 10h */ + U32 EnclosureMapping; /* 10h */ } CONFIG_PAGE_SAS_DEVICE_2, MPI_POINTER PTR_CONFIG_PAGE_SAS_DEVICE_2, SasDevicePage2_t, MPI_POINTER pSasDevicePage2_t; -#define MPI_SASDEVICE2_PAGEVERSION (0x00) +#define MPI_SASDEVICE2_PAGEVERSION (0x01) + +/* defines for SAS Device Page 2 EnclosureMapping field */ +#define MPI_SASDEVICE2_ENC_MAP_MASK_MISSING_COUNT (0x0000000F) +#define MPI_SASDEVICE2_ENC_MAP_SHIFT_MISSING_COUNT (0) +#define MPI_SASDEVICE2_ENC_MAP_MASK_NUM_SLOTS (0x000007F0) +#define MPI_SASDEVICE2_ENC_MAP_SHIFT_NUM_SLOTS (4) +#define MPI_SASDEVICE2_ENC_MAP_MASK_START_INDEX (0x001FF800) +#define MPI_SASDEVICE2_ENC_MAP_SHIFT_START_INDEX (11) /**************************************************************************** @@ -2598,7 +2644,8 @@ typedef struct _CONFIG_PAGE_SAS_DEVICE_2 typedef struct _CONFIG_PAGE_SAS_PHY_0 { CONFIG_EXTENDED_PAGE_HEADER Header; /* 00h */ - U32 Reserved1; /* 08h */ + U16 OwnerDevHandle; /* 08h */ + U16 Reserved1; /* 0Ah */ U64 SASAddress; /* 0Ch */ U16 AttachedDevHandle; /* 14h */ U8 AttachedPhyIdentifier; /* 16h */ @@ -2607,12 +2654,12 @@ typedef struct _CONFIG_PAGE_SAS_PHY_0 U8 ProgrammedLinkRate; /* 20h */ U8 HwLinkRate; /* 21h */ U8 ChangeCount; /* 22h */ - U8 Reserved3; /* 23h */ + U8 Flags; /* 23h */ U32 PhyInfo; /* 24h */ } CONFIG_PAGE_SAS_PHY_0, MPI_POINTER PTR_CONFIG_PAGE_SAS_PHY_0, SasPhyPage0_t, MPI_POINTER pSasPhyPage0_t; -#define MPI_SASPHY0_PAGEVERSION (0x00) +#define MPI_SASPHY0_PAGEVERSION (0x01) /* values for SAS PHY Page 0 ProgrammedLinkRate field */ #define MPI_SAS_PHY0_PRATE_MAX_RATE_MASK (0xF0) @@ -2632,6 +2679,9 @@ typedef struct _CONFIG_PAGE_SAS_PHY_0 #define MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5 (0x08) #define MPI_SAS_PHY0_HWRATE_MIN_RATE_3_0 (0x09) +/* values for SAS PHY Page 0 Flags field */ +#define MPI_SAS_PHY0_FLAGS_SGPIO_DIRECT_ATTACH_ENC (0x01) + /* values for SAS PHY Page 0 PhyInfo field */ #define MPI_SAS_PHY0_PHYINFO_SATA_PORT_ACTIVE (0x00004000) #define MPI_SAS_PHY0_PHYINFO_SATA_PORT_SELECTOR (0x00002000) @@ -2690,7 +2740,7 @@ typedef struct _CONFIG_PAGE_SAS_ENCLOSURE_0 } CONFIG_PAGE_SAS_ENCLOSURE_0, MPI_POINTER PTR_CONFIG_PAGE_SAS_ENCLOSURE_0, SasEnclosurePage0_t, MPI_POINTER pSasEnclosurePage0_t; -#define MPI_SASENCLOSURE0_PAGEVERSION (0x00) +#define MPI_SASENCLOSURE0_PAGEVERSION (0x01) /* values for SAS Enclosure Page 0 Flags field */ #define MPI_SAS_ENCLS0_FLAGS_SEP_BUS_ID_VALID (0x0020) @@ -2702,6 +2752,7 @@ typedef struct _CONFIG_PAGE_SAS_ENCLOSURE_0 #define MPI_SAS_ENCLS0_FLAGS_MNG_IOC_SGPIO (0x0002) #define MPI_SAS_ENCLS0_FLAGS_MNG_EXP_SGPIO (0x0003) #define MPI_SAS_ENCLS0_FLAGS_MNG_SES_ENCLOSURE (0x0004) +#define MPI_SAS_ENCLS0_FLAGS_MNG_IOC_GPIO (0x0005) /**************************************************************************** diff --git a/drivers/message/fusion/lsi/mpi_history.txt b/drivers/message/fusion/lsi/mpi_history.txt index c9edbee41edf..1a30ef16adb4 100644 --- a/drivers/message/fusion/lsi/mpi_history.txt +++ b/drivers/message/fusion/lsi/mpi_history.txt @@ -6,17 +6,17 @@ Copyright (c) 2000-2005 LSI Logic Corporation. --------------------------------------- - Header Set Release Version: 01.05.09 + Header Set Release Version: 01.05.10 Header Set Release Date: 03-11-05 --------------------------------------- Filename Current version Prior version ---------- --------------- ------------- - mpi.h 01.05.07 01.05.06 - mpi_ioc.h 01.05.08 01.05.07 - mpi_cnfg.h 01.05.08 01.05.07 - mpi_init.h 01.05.04 01.05.03 - mpi_targ.h 01.05.04 01.05.03 + mpi.h 01.05.08 01.05.07 + mpi_ioc.h 01.05.09 01.05.08 + mpi_cnfg.h 01.05.09 01.05.08 + mpi_init.h 01.05.05 01.05.04 + mpi_targ.h 01.05.05 01.05.04 mpi_fc.h 01.05.01 01.05.01 mpi_lan.h 01.05.01 01.05.01 mpi_raid.h 01.05.02 01.05.02 @@ -24,7 +24,7 @@ mpi_inb.h 01.05.01 01.05.01 mpi_sas.h 01.05.01 01.05.01 mpi_type.h 01.05.01 01.05.01 - mpi_history.txt 01.05.09 01.05.08 + mpi_history.txt 01.05.09 01.05.09 * Date Version Description @@ -88,6 +88,9 @@ mpi.h * 03-11-05 01.05.07 Removed function codes for SCSI IO 32 and * TargetAssistExtended requests. * Removed EEDP IOCStatus codes. + * 06-24-05 01.05.08 Added function codes for SCSI IO 32 and + * TargetAssistExtended requests. + * Added EEDP IOCStatus codes. * -------------------------------------------------------------------------- mpi_ioc.h @@ -159,6 +162,8 @@ mpi_ioc.h * Reply and IOC Init Request. * 03-11-05 01.05.08 Added family code for 1068E family. * Removed IOCFacts Reply EEDP Capability bit. + * 06-24-05 01.05.09 Added 5 new IOCFacts Reply IOCCapabilities bits. + * Added Max SATA Targets to SAS Discovery Error event. * -------------------------------------------------------------------------- mpi_cnfg.h @@ -380,6 +385,23 @@ mpi_cnfg.h * New physical mapping mode in SAS IO Unit Page 2. * Added CONFIG_PAGE_SAS_ENCLOSURE_0. * Added Slot and Enclosure fields to SAS Device Page 0. + * 06-24-05 01.05.09 Added EEDP defines to IOC Page 1. + * Added more RAID type defines to IOC Page 2. + * Added Port Enable Delay settings to BIOS Page 1. + * Added Bad Block Table Full define to RAID Volume Page 0. + * Added Previous State defines to RAID Physical Disk + * Page 0. + * Added Max Sata Targets define for DiscoveryStatus field + * of SAS IO Unit Page 0. + * Added Device Self Test to Control Flags of SAS IO Unit + * Page 1. + * Added Direct Attach Starting Slot Number define for SAS + * IO Unit Page 2. + * Added new fields in SAS Device Page 2 for enclosure + * mapping. + * Added OwnerDevHandle and Flags field to SAS PHY Page 0. + * Added IOC GPIO Flags define to SAS Enclosure Page 0. + * Fixed the value for MPI_SAS_IOUNIT1_CONTROL_DEV_SATA_SUPPORT. * -------------------------------------------------------------------------- mpi_init.h @@ -418,6 +440,8 @@ mpi_init.h * Modified SCSI Enclosure Processor Request and Reply to * support Enclosure/Slot addressing rather than WWID * addressing. + * 06-24-05 01.05.05 Added SCSI IO 32 structures and defines. + * Added four new defines for SEP SlotStatus. * -------------------------------------------------------------------------- mpi_targ.h @@ -461,6 +485,7 @@ mpi_targ.h * 10-05-04 01.05.02 MSG_TARGET_CMD_BUFFER_POST_BASE_LIST_REPLY added. * 02-22-05 01.05.03 Changed a comment. * 03-11-05 01.05.04 Removed TargetAssistExtended Request. + * 06-24-05 01.05.05 Added TargetAssistExtended structures and defines. * -------------------------------------------------------------------------- mpi_fc.h @@ -571,20 +596,20 @@ mpi_type.h mpi_history.txt Parts list history -Filename 01.05.09 ----------- -------- -mpi.h 01.05.07 -mpi_ioc.h 01.05.08 -mpi_cnfg.h 01.05.08 -mpi_init.h 01.05.04 -mpi_targ.h 01.05.04 -mpi_fc.h 01.05.01 -mpi_lan.h 01.05.01 -mpi_raid.h 01.05.02 -mpi_tool.h 01.05.03 -mpi_inb.h 01.05.01 -mpi_sas.h 01.05.01 -mpi_type.h 01.05.01 +Filename 01.05.10 01.05.09 +---------- -------- -------- +mpi.h 01.05.08 01.05.07 +mpi_ioc.h 01.05.09 01.05.08 +mpi_cnfg.h 01.05.09 01.05.08 +mpi_init.h 01.05.05 01.05.04 +mpi_targ.h 01.05.05 01.05.04 +mpi_fc.h 01.05.01 01.05.01 +mpi_lan.h 01.05.01 01.05.01 +mpi_raid.h 01.05.02 01.05.02 +mpi_tool.h 01.05.03 01.05.03 +mpi_inb.h 01.05.01 01.05.01 +mpi_sas.h 01.05.01 01.05.01 +mpi_type.h 01.05.01 01.05.01 Filename 01.05.08 01.05.07 01.05.06 01.05.05 01.05.04 01.05.03 ---------- -------- -------- -------- -------- -------- -------- diff --git a/drivers/message/fusion/lsi/mpi_init.h b/drivers/message/fusion/lsi/mpi_init.h index aca035801a86..d5af75afbd94 100644 --- a/drivers/message/fusion/lsi/mpi_init.h +++ b/drivers/message/fusion/lsi/mpi_init.h @@ -6,7 +6,7 @@ * Title: MPI initiator mode messages and structures * Creation Date: June 8, 2000 * - * mpi_init.h Version: 01.05.04 + * mpi_init.h Version: 01.05.05 * * Version History * --------------- @@ -48,6 +48,8 @@ * Modified SCSI Enclosure Processor Request and Reply to * support Enclosure/Slot addressing rather than WWID * addressing. + * 06-24-05 01.05.05 Added SCSI IO 32 structures and defines. + * Added four new defines for SEP SlotStatus. * -------------------------------------------------------------------------- */ @@ -202,6 +204,197 @@ typedef struct _MSG_SCSI_IO_REPLY #define MPI_SCSI_TASKTAG_UNKNOWN (0xFFFF) +/****************************************************************************/ +/* SCSI IO 32 messages and associated structures */ +/****************************************************************************/ + +typedef struct +{ + U8 CDB[20]; /* 00h */ + U32 PrimaryReferenceTag; /* 14h */ + U16 PrimaryApplicationTag; /* 18h */ + U16 PrimaryApplicationTagMask; /* 1Ah */ + U32 TransferLength; /* 1Ch */ +} MPI_SCSI_IO32_CDB_EEDP32, MPI_POINTER PTR_MPI_SCSI_IO32_CDB_EEDP32, + MpiScsiIo32CdbEedp32_t, MPI_POINTER pMpiScsiIo32CdbEedp32_t; + +typedef struct +{ + U8 CDB[16]; /* 00h */ + U32 DataLength; /* 10h */ + U32 PrimaryReferenceTag; /* 14h */ + U16 PrimaryApplicationTag; /* 18h */ + U16 PrimaryApplicationTagMask; /* 1Ah */ + U32 TransferLength; /* 1Ch */ +} MPI_SCSI_IO32_CDB_EEDP16, MPI_POINTER PTR_MPI_SCSI_IO32_CDB_EEDP16, + MpiScsiIo32CdbEedp16_t, MPI_POINTER pMpiScsiIo32CdbEedp16_t; + +typedef union +{ + U8 CDB32[32]; + MPI_SCSI_IO32_CDB_EEDP32 EEDP32; + MPI_SCSI_IO32_CDB_EEDP16 EEDP16; + SGE_SIMPLE_UNION SGE; +} MPI_SCSI_IO32_CDB_UNION, MPI_POINTER PTR_MPI_SCSI_IO32_CDB_UNION, + MpiScsiIo32Cdb_t, MPI_POINTER pMpiScsiIo32Cdb_t; + +typedef struct +{ + U8 TargetID; /* 00h */ + U8 Bus; /* 01h */ + U16 Reserved1; /* 02h */ + U32 Reserved2; /* 04h */ +} MPI_SCSI_IO32_BUS_TARGET_ID_FORM, MPI_POINTER PTR_MPI_SCSI_IO32_BUS_TARGET_ID_FORM, + MpiScsiIo32BusTargetIdForm_t, MPI_POINTER pMpiScsiIo32BusTargetIdForm_t; + +typedef union +{ + MPI_SCSI_IO32_BUS_TARGET_ID_FORM SCSIID; + U64 WWID; +} MPI_SCSI_IO32_ADDRESS, MPI_POINTER PTR_MPI_SCSI_IO32_ADDRESS, + MpiScsiIo32Address_t, MPI_POINTER pMpiScsiIo32Address_t; + +typedef struct _MSG_SCSI_IO32_REQUEST +{ + U8 Port; /* 00h */ + U8 Reserved1; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U8 CDBLength; /* 04h */ + U8 SenseBufferLength; /* 05h */ + U8 Flags; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U8 LUN[8]; /* 0Ch */ + U32 Control; /* 14h */ + MPI_SCSI_IO32_CDB_UNION CDB; /* 18h */ + U32 DataLength; /* 38h */ + U32 BidirectionalDataLength; /* 3Ch */ + U32 SecondaryReferenceTag; /* 40h */ + U16 SecondaryApplicationTag; /* 44h */ + U16 Reserved2; /* 46h */ + U16 EEDPFlags; /* 48h */ + U16 ApplicationTagTranslationMask; /* 4Ah */ + U32 EEDPBlockSize; /* 4Ch */ + MPI_SCSI_IO32_ADDRESS DeviceAddress; /* 50h */ + U8 SGLOffset0; /* 58h */ + U8 SGLOffset1; /* 59h */ + U8 SGLOffset2; /* 5Ah */ + U8 SGLOffset3; /* 5Bh */ + U32 Reserved3; /* 5Ch */ + U32 Reserved4; /* 60h */ + U32 SenseBufferLowAddr; /* 64h */ + SGE_IO_UNION SGL; /* 68h */ +} MSG_SCSI_IO32_REQUEST, MPI_POINTER PTR_MSG_SCSI_IO32_REQUEST, + SCSIIO32Request_t, MPI_POINTER pSCSIIO32Request_t; + +/* SCSI IO 32 MsgFlags bits */ +#define MPI_SCSIIO32_MSGFLGS_SENSE_WIDTH (0x01) +#define MPI_SCSIIO32_MSGFLGS_SENSE_WIDTH_32 (0x00) +#define MPI_SCSIIO32_MSGFLGS_SENSE_WIDTH_64 (0x01) + +#define MPI_SCSIIO32_MSGFLGS_SENSE_LOCATION (0x02) +#define MPI_SCSIIO32_MSGFLGS_SENSE_LOC_HOST (0x00) +#define MPI_SCSIIO32_MSGFLGS_SENSE_LOC_IOC (0x02) + +#define MPI_SCSIIO32_MSGFLGS_CMD_DETERMINES_DATA_DIR (0x04) +#define MPI_SCSIIO32_MSGFLGS_SGL_OFFSETS_CHAINS (0x08) +#define MPI_SCSIIO32_MSGFLGS_MULTICAST (0x10) +#define MPI_SCSIIO32_MSGFLGS_BIDIRECTIONAL (0x20) +#define MPI_SCSIIO32_MSGFLGS_LARGE_CDB (0x40) + +/* SCSI IO 32 Flags bits */ +#define MPI_SCSIIO32_FLAGS_FORM_MASK (0x03) +#define MPI_SCSIIO32_FLAGS_FORM_SCSIID (0x00) +#define MPI_SCSIIO32_FLAGS_FORM_WWID (0x01) + +/* SCSI IO 32 LUN fields */ +#define MPI_SCSIIO32_LUN_FIRST_LEVEL_ADDRESSING (0x0000FFFF) +#define MPI_SCSIIO32_LUN_SECOND_LEVEL_ADDRESSING (0xFFFF0000) +#define MPI_SCSIIO32_LUN_THIRD_LEVEL_ADDRESSING (0x0000FFFF) +#define MPI_SCSIIO32_LUN_FOURTH_LEVEL_ADDRESSING (0xFFFF0000) +#define MPI_SCSIIO32_LUN_LEVEL_1_WORD (0xFF00) +#define MPI_SCSIIO32_LUN_LEVEL_1_DWORD (0x0000FF00) + +/* SCSI IO 32 Control bits */ +#define MPI_SCSIIO32_CONTROL_DATADIRECTION_MASK (0x03000000) +#define MPI_SCSIIO32_CONTROL_NODATATRANSFER (0x00000000) +#define MPI_SCSIIO32_CONTROL_WRITE (0x01000000) +#define MPI_SCSIIO32_CONTROL_READ (0x02000000) +#define MPI_SCSIIO32_CONTROL_BIDIRECTIONAL (0x03000000) + +#define MPI_SCSIIO32_CONTROL_ADDCDBLEN_MASK (0xFC000000) +#define MPI_SCSIIO32_CONTROL_ADDCDBLEN_SHIFT (26) + +#define MPI_SCSIIO32_CONTROL_TASKATTRIBUTE_MASK (0x00000700) +#define MPI_SCSIIO32_CONTROL_SIMPLEQ (0x00000000) +#define MPI_SCSIIO32_CONTROL_HEADOFQ (0x00000100) +#define MPI_SCSIIO32_CONTROL_ORDEREDQ (0x00000200) +#define MPI_SCSIIO32_CONTROL_ACAQ (0x00000400) +#define MPI_SCSIIO32_CONTROL_UNTAGGED (0x00000500) +#define MPI_SCSIIO32_CONTROL_NO_DISCONNECT (0x00000700) + +#define MPI_SCSIIO32_CONTROL_TASKMANAGE_MASK (0x00FF0000) +#define MPI_SCSIIO32_CONTROL_OBSOLETE (0x00800000) +#define MPI_SCSIIO32_CONTROL_CLEAR_ACA_RSV (0x00400000) +#define MPI_SCSIIO32_CONTROL_TARGET_RESET (0x00200000) +#define MPI_SCSIIO32_CONTROL_LUN_RESET_RSV (0x00100000) +#define MPI_SCSIIO32_CONTROL_RESERVED (0x00080000) +#define MPI_SCSIIO32_CONTROL_CLR_TASK_SET_RSV (0x00040000) +#define MPI_SCSIIO32_CONTROL_ABORT_TASK_SET (0x00020000) +#define MPI_SCSIIO32_CONTROL_RESERVED2 (0x00010000) + +/* SCSI IO 32 EEDPFlags */ +#define MPI_SCSIIO32_EEDPFLAGS_MASK_OP (0x0007) +#define MPI_SCSIIO32_EEDPFLAGS_NOOP_OP (0x0000) +#define MPI_SCSIIO32_EEDPFLAGS_CHK_OP (0x0001) +#define MPI_SCSIIO32_EEDPFLAGS_STRIP_OP (0x0002) +#define MPI_SCSIIO32_EEDPFLAGS_CHKRM_OP (0x0003) +#define MPI_SCSIIO32_EEDPFLAGS_INSERT_OP (0x0004) +#define MPI_SCSIIO32_EEDPFLAGS_REPLACE_OP (0x0006) +#define MPI_SCSIIO32_EEDPFLAGS_CHKREGEN_OP (0x0007) + +#define MPI_SCSIIO32_EEDPFLAGS_PASS_REF_TAG (0x0008) +#define MPI_SCSIIO32_EEDPFLAGS_8_9THS_MODE (0x0010) + +#define MPI_SCSIIO32_EEDPFLAGS_T10_CHK_MASK (0x0700) +#define MPI_SCSIIO32_EEDPFLAGS_T10_CHK_GUARD (0x0100) +#define MPI_SCSIIO32_EEDPFLAGS_T10_CHK_REFTAG (0x0200) +#define MPI_SCSIIO32_EEDPFLAGS_T10_CHK_LBATAG (0x0400) +#define MPI_SCSIIO32_EEDPFLAGS_T10_CHK_SHIFT (8) + +#define MPI_SCSIIO32_EEDPFLAGS_INC_SEC_APPTAG (0x1000) +#define MPI_SCSIIO32_EEDPFLAGS_INC_PRI_APPTAG (0x2000) +#define MPI_SCSIIO32_EEDPFLAGS_INC_SEC_REFTAG (0x4000) +#define MPI_SCSIIO32_EEDPFLAGS_INC_PRI_REFTAG (0x8000) + + +/* SCSIIO32 IO reply structure */ +typedef struct _MSG_SCSIIO32_IO_REPLY +{ + U8 Port; /* 00h */ + U8 Reserved1; /* 01h */ + U8 MsgLength; /* 02h */ + U8 Function; /* 03h */ + U8 CDBLength; /* 04h */ + U8 SenseBufferLength; /* 05h */ + U8 Flags; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U8 SCSIStatus; /* 0Ch */ + U8 SCSIState; /* 0Dh */ + U16 IOCStatus; /* 0Eh */ + U32 IOCLogInfo; /* 10h */ + U32 TransferCount; /* 14h */ + U32 SenseCount; /* 18h */ + U32 ResponseInfo; /* 1Ch */ + U16 TaskTag; /* 20h */ + U16 Reserved2; /* 22h */ + U32 BidirectionalTransferCount; /* 24h */ +} MSG_SCSIIO32_IO_REPLY, MPI_POINTER PTR_MSG_SCSIIO32_IO_REPLY, + SCSIIO32Reply_t, MPI_POINTER pSCSIIO32Reply_t; + + /****************************************************************************/ /* SCSI Task Management messages */ /****************************************************************************/ @@ -310,10 +503,14 @@ typedef struct _MSG_SEP_REQUEST #define MPI_SEP_REQ_SLOTSTATUS_UNCONFIGURED (0x00000080) #define MPI_SEP_REQ_SLOTSTATUS_HOT_SPARE (0x00000100) #define MPI_SEP_REQ_SLOTSTATUS_REBUILD_STOPPED (0x00000200) +#define MPI_SEP_REQ_SLOTSTATUS_REQ_CONSISTENCY_CHECK (0x00001000) +#define MPI_SEP_REQ_SLOTSTATUS_DISABLE (0x00002000) +#define MPI_SEP_REQ_SLOTSTATUS_REQ_RESERVED_DEVICE (0x00004000) #define MPI_SEP_REQ_SLOTSTATUS_IDENTIFY_REQUEST (0x00020000) #define MPI_SEP_REQ_SLOTSTATUS_REQUEST_REMOVE (0x00040000) #define MPI_SEP_REQ_SLOTSTATUS_REQUEST_INSERT (0x00080000) #define MPI_SEP_REQ_SLOTSTATUS_DO_NOT_MOVE (0x00400000) +#define MPI_SEP_REQ_SLOTSTATUS_ACTIVE (0x00800000) #define MPI_SEP_REQ_SLOTSTATUS_B_ENABLE_BYPASS (0x04000000) #define MPI_SEP_REQ_SLOTSTATUS_A_ENABLE_BYPASS (0x08000000) #define MPI_SEP_REQ_SLOTSTATUS_DEV_OFF (0x10000000) @@ -352,11 +549,15 @@ typedef struct _MSG_SEP_REPLY #define MPI_SEP_REPLY_SLOTSTATUS_UNCONFIGURED (0x00000080) #define MPI_SEP_REPLY_SLOTSTATUS_HOT_SPARE (0x00000100) #define MPI_SEP_REPLY_SLOTSTATUS_REBUILD_STOPPED (0x00000200) +#define MPI_SEP_REPLY_SLOTSTATUS_CONSISTENCY_CHECK (0x00001000) +#define MPI_SEP_REPLY_SLOTSTATUS_DISABLE (0x00002000) +#define MPI_SEP_REPLY_SLOTSTATUS_RESERVED_DEVICE (0x00004000) #define MPI_SEP_REPLY_SLOTSTATUS_REPORT (0x00010000) #define MPI_SEP_REPLY_SLOTSTATUS_IDENTIFY_REQUEST (0x00020000) #define MPI_SEP_REPLY_SLOTSTATUS_REMOVE_READY (0x00040000) #define MPI_SEP_REPLY_SLOTSTATUS_INSERT_READY (0x00080000) #define MPI_SEP_REPLY_SLOTSTATUS_DO_NOT_REMOVE (0x00400000) +#define MPI_SEP_REPLY_SLOTSTATUS_ACTIVE (0x00800000) #define MPI_SEP_REPLY_SLOTSTATUS_B_BYPASS_ENABLED (0x01000000) #define MPI_SEP_REPLY_SLOTSTATUS_A_BYPASS_ENABLED (0x02000000) #define MPI_SEP_REPLY_SLOTSTATUS_B_ENABLE_BYPASS (0x04000000) diff --git a/drivers/message/fusion/lsi/mpi_ioc.h b/drivers/message/fusion/lsi/mpi_ioc.h index f91eb4efe8cc..93b70e2b4266 100644 --- a/drivers/message/fusion/lsi/mpi_ioc.h +++ b/drivers/message/fusion/lsi/mpi_ioc.h @@ -6,7 +6,7 @@ * Title: MPI IOC, Port, Event, FW Download, and FW Upload messages * Creation Date: August 11, 2000 * - * mpi_ioc.h Version: 01.05.08 + * mpi_ioc.h Version: 01.05.09 * * Version History * --------------- @@ -81,6 +81,8 @@ * Reply and IOC Init Request. * 03-11-05 01.05.08 Added family code for 1068E family. * Removed IOCFacts Reply EEDP Capability bit. + * 06-24-05 01.05.09 Added 5 new IOCFacts Reply IOCCapabilities bits. + * Added Max SATA Targets to SAS Discovery Error event. * -------------------------------------------------------------------------- */ @@ -261,7 +263,11 @@ typedef struct _MSG_IOC_FACTS_REPLY #define MPI_IOCFACTS_CAPABILITY_DIAG_TRACE_BUFFER (0x00000008) #define MPI_IOCFACTS_CAPABILITY_SNAPSHOT_BUFFER (0x00000010) #define MPI_IOCFACTS_CAPABILITY_EXTENDED_BUFFER (0x00000020) - +#define MPI_IOCFACTS_CAPABILITY_EEDP (0x00000040) +#define MPI_IOCFACTS_CAPABILITY_BIDIRECTIONAL (0x00000080) +#define MPI_IOCFACTS_CAPABILITY_MULTICAST (0x00000100) +#define MPI_IOCFACTS_CAPABILITY_SCSIIO32 (0x00000200) +#define MPI_IOCFACTS_CAPABILITY_NO_SCSIIO16 (0x00000400) /***************************************************************************** @@ -677,6 +683,7 @@ typedef struct _EVENT_DATA_DISCOVERY_ERROR #define MPI_EVENT_DSCVRY_ERR_DS_MULTPL_SUBTRACTIVE (0x00000200) #define MPI_EVENT_DSCVRY_ERR_DS_TABLE_TO_TABLE (0x00000400) #define MPI_EVENT_DSCVRY_ERR_DS_MULTPL_PATHS (0x00000800) +#define MPI_EVENT_DSCVRY_ERR_DS_MAX_SATA_TARGETS (0x00001000) /***************************************************************************** diff --git a/drivers/message/fusion/lsi/mpi_targ.h b/drivers/message/fusion/lsi/mpi_targ.h index 623901fd82be..3f462859ceea 100644 --- a/drivers/message/fusion/lsi/mpi_targ.h +++ b/drivers/message/fusion/lsi/mpi_targ.h @@ -6,7 +6,7 @@ * Title: MPI Target mode messages and structures * Creation Date: June 22, 2000 * - * mpi_targ.h Version: 01.05.04 + * mpi_targ.h Version: 01.05.05 * * Version History * --------------- @@ -53,6 +53,7 @@ * 10-05-04 01.05.02 MSG_TARGET_CMD_BUFFER_POST_BASE_LIST_REPLY added. * 02-22-05 01.05.03 Changed a comment. * 03-11-05 01.05.04 Removed TargetAssistExtended Request. + * 06-24-05 01.05.05 Added TargetAssistExtended structures and defines. * -------------------------------------------------------------------------- */ @@ -370,6 +371,77 @@ typedef struct _MSG_TARGET_ERROR_REPLY TargetErrorReply_t, MPI_POINTER pTargetErrorReply_t; +/****************************************************************************/ +/* Target Assist Extended Request */ +/****************************************************************************/ + +typedef struct _MSG_TARGET_ASSIST_EXT_REQUEST +{ + U8 StatusCode; /* 00h */ + U8 TargetAssistFlags; /* 01h */ + U8 ChainOffset; /* 02h */ + U8 Function; /* 03h */ + U16 QueueTag; /* 04h */ + U8 Reserved1; /* 06h */ + U8 MsgFlags; /* 07h */ + U32 MsgContext; /* 08h */ + U32 ReplyWord; /* 0Ch */ + U8 LUN[8]; /* 10h */ + U32 RelativeOffset; /* 18h */ + U32 Reserved2; /* 1Ch */ + U32 Reserved3; /* 20h */ + U32 PrimaryReferenceTag; /* 24h */ + U16 PrimaryApplicationTag; /* 28h */ + U16 PrimaryApplicationTagMask; /* 2Ah */ + U32 Reserved4; /* 2Ch */ + U32 DataLength; /* 30h */ + U32 BidirectionalDataLength; /* 34h */ + U32 SecondaryReferenceTag; /* 38h */ + U16 SecondaryApplicationTag; /* 3Ch */ + U16 Reserved5; /* 3Eh */ + U16 EEDPFlags; /* 40h */ + U16 ApplicationTagTranslationMask; /* 42h */ + U32 EEDPBlockSize; /* 44h */ + U8 SGLOffset0; /* 48h */ + U8 SGLOffset1; /* 49h */ + U8 SGLOffset2; /* 4Ah */ + U8 SGLOffset3; /* 4Bh */ + U32 Reserved6; /* 4Ch */ + SGE_IO_UNION SGL[1]; /* 50h */ +} MSG_TARGET_ASSIST_EXT_REQUEST, MPI_POINTER PTR_MSG_TARGET_ASSIST_EXT_REQUEST, + TargetAssistExtRequest_t, MPI_POINTER pTargetAssistExtRequest_t; + +/* see the defines after MSG_TARGET_ASSIST_REQUEST for TargetAssistFlags */ + +/* defines for the MsgFlags field */ +#define TARGET_ASSIST_EXT_MSGFLAGS_BIDIRECTIONAL (0x20) +#define TARGET_ASSIST_EXT_MSGFLAGS_MULTICAST (0x10) +#define TARGET_ASSIST_EXT_MSGFLAGS_SGL_OFFSET_CHAINS (0x08) + +/* defines for the EEDPFlags field */ +#define TARGET_ASSIST_EXT_EEDP_MASK_OP (0x0007) +#define TARGET_ASSIST_EXT_EEDP_NOOP_OP (0x0000) +#define TARGET_ASSIST_EXT_EEDP_CHK_OP (0x0001) +#define TARGET_ASSIST_EXT_EEDP_STRIP_OP (0x0002) +#define TARGET_ASSIST_EXT_EEDP_CHKRM_OP (0x0003) +#define TARGET_ASSIST_EXT_EEDP_INSERT_OP (0x0004) +#define TARGET_ASSIST_EXT_EEDP_REPLACE_OP (0x0006) +#define TARGET_ASSIST_EXT_EEDP_CHKREGEN_OP (0x0007) + +#define TARGET_ASSIST_EXT_EEDP_PASS_REF_TAG (0x0008) + +#define TARGET_ASSIST_EXT_EEDP_T10_CHK_MASK (0x0700) +#define TARGET_ASSIST_EXT_EEDP_T10_CHK_GUARD (0x0100) +#define TARGET_ASSIST_EXT_EEDP_T10_CHK_APPTAG (0x0200) +#define TARGET_ASSIST_EXT_EEDP_T10_CHK_REFTAG (0x0400) +#define TARGET_ASSIST_EXT_EEDP_T10_CHK_SHIFT (8) + +#define TARGET_ASSIST_EXT_EEDP_INC_SEC_APPTAG (0x1000) +#define TARGET_ASSIST_EXT_EEDP_INC_PRI_APPTAG (0x2000) +#define TARGET_ASSIST_EXT_EEDP_INC_SEC_REFTAG (0x4000) +#define TARGET_ASSIST_EXT_EEDP_INC_PRI_REFTAG (0x8000) + + /****************************************************************************/ /* Target Status Send Request */ /****************************************************************************/ From 637fa99b86a00a0b5767a982b83a512ff48ad6d2 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 18 Aug 2005 16:25:44 +0200 Subject: [PATCH 091/114] [SCSI] fusion: endianess fixes Assorted endianess fixes. I'll work on full endianess annotations later. Acked by: Moore, Eric Dean Signed-off-by: James Bottomley --- drivers/message/fusion/mptbase.c | 6 +++--- drivers/message/fusion/mptctl.c | 2 +- drivers/message/fusion/mptscsih.c | 24 ++++++++++++------------ 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index 284202766804..35444ba4e78a 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -2185,7 +2185,7 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason) facts->IOCExceptions = le16_to_cpu(facts->IOCExceptions); facts->IOCStatus = le16_to_cpu(facts->IOCStatus); facts->IOCLogInfo = le32_to_cpu(facts->IOCLogInfo); - status = facts->IOCStatus & MPI_IOCSTATUS_MASK; + status = le16_to_cpu(facts->IOCStatus) & MPI_IOCSTATUS_MASK; /* CHECKME! IOCStatus, IOCLogInfo */ facts->ReplyQueueDepth = le16_to_cpu(facts->ReplyQueueDepth); @@ -4823,8 +4823,8 @@ mpt_toolbox(MPT_ADAPTER *ioc, CONFIGPARMS *pCfg) pReq->Reserved3 = 0; pReq->NumAddressBytes = 0x01; pReq->Reserved4 = 0; - pReq->DataLength = 0x04; - pdev = (struct pci_dev *) ioc->pcidev; + pReq->DataLength = cpu_to_le16(0x04); + pdev = ioc->pcidev; if (pdev->devfn & 1) pReq->DeviceAddr = 0xB2; else diff --git a/drivers/message/fusion/mptctl.c b/drivers/message/fusion/mptctl.c index e63a3fd6b706..7577c2417e2e 100644 --- a/drivers/message/fusion/mptctl.c +++ b/drivers/message/fusion/mptctl.c @@ -242,7 +242,7 @@ mptctl_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, MPT_FRAME_HDR *reply) /* Set the command status to GOOD if IOC Status is GOOD * OR if SCSI I/O cmd and data underrun or recovered error. */ - iocStatus = reply->u.reply.IOCStatus & MPI_IOCSTATUS_MASK; + iocStatus = le16_to_cpu(reply->u.reply.IOCStatus) & MPI_IOCSTATUS_MASK; if (iocStatus == MPI_IOCSTATUS_SUCCESS) ioc->ioctl->status |= MPT_IOCTL_STATUS_COMMAND_GOOD; diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index b774f45dfde4..cd4e8c0853d0 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -3447,7 +3447,7 @@ mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) * some type of error occurred. */ MpiRaidActionReply_t *pr = (MpiRaidActionReply_t *)mr; - if (pr->ActionStatus == MPI_RAID_ACTION_ASTATUS_SUCCESS) + if (le16_to_cpu(pr->ActionStatus) == MPI_RAID_ACTION_ASTATUS_SUCCESS) completionCode = MPT_SCANDV_GOOD; else completionCode = MPT_SCANDV_SOME_ERROR; @@ -3996,9 +3996,9 @@ mptscsih_synchronize_cache(MPT_SCSI_HOST *hd, int portnum) dnegoprintk(("syncronize cache: id=%d width=0 factor=MPT_ASYNC " "offset=0 negoFlags=%x request=%x config=%x\n", id, flags, requested, configuration)); - pcfg1Data->RequestedParameters = le32_to_cpu(requested); + pcfg1Data->RequestedParameters = cpu_to_le32(requested); pcfg1Data->Reserved = 0; - pcfg1Data->Configuration = le32_to_cpu(configuration); + pcfg1Data->Configuration = cpu_to_le32(configuration); cfg.pageAddr = (bus<<8) | id; mpt_config(hd->ioc, &cfg); } @@ -5248,7 +5248,7 @@ mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage) /* Update tmax values with those from Device Page 0.*/ pPage0 = (SCSIDevicePage0_t *) pPage; if (pPage0) { - val = cpu_to_le32(pPage0->NegotiatedParameters); + val = le32_to_cpu(pPage0->NegotiatedParameters); dv->max.width = val & MPI_SCSIDEVPAGE0_NP_WIDE ? 1 : 0; dv->max.offset = (val&MPI_SCSIDEVPAGE0_NP_NEG_SYNC_OFFSET_MASK) >> 16; dv->max.factor = (val&MPI_SCSIDEVPAGE0_NP_NEG_SYNC_PERIOD_MASK) >> 8; @@ -5276,12 +5276,12 @@ mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage) dv->now.offset, &val, &configuration, dv->now.flags); dnegoprintk(("Setting Max: id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x config=%x\n", id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags, val, configuration)); - pPage1->RequestedParameters = le32_to_cpu(val); + pPage1->RequestedParameters = cpu_to_le32(val); pPage1->Reserved = 0; - pPage1->Configuration = le32_to_cpu(configuration); + pPage1->Configuration = cpu_to_le32(configuration); } - ddvprintk(("id=%d width=%d factor=%x offset=%x flags=%x request=%x configuration=%x\n", + ddvprintk(("id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x configuration=%x\n", id, dv->now.width, dv->now.factor, dv->now.offset, dv->now.flags, val, configuration)); break; @@ -5301,9 +5301,9 @@ mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage) offset, &val, &configuration, negoFlags); dnegoprintk(("Setting Min: id=%d width=%d factor=%x offset=%x negoFlags=%x request=%x config=%x\n", id, width, factor, offset, negoFlags, val, configuration)); - pPage1->RequestedParameters = le32_to_cpu(val); + pPage1->RequestedParameters = cpu_to_le32(val); pPage1->Reserved = 0; - pPage1->Configuration = le32_to_cpu(configuration); + pPage1->Configuration = cpu_to_le32(configuration); } ddvprintk(("id=%d width=%d factor=%x offset=%x request=%x config=%x negoFlags=%x\n", id, width, factor, offset, val, configuration, negoFlags)); @@ -5377,12 +5377,12 @@ mptscsih_dv_parms(MPT_SCSI_HOST *hd, DVPARAMETERS *dv,void *pPage) if (pPage1) { mptscsih_setDevicePage1Flags (width, factor, offset, &val, &configuration, dv->now.flags); - dnegoprintk(("Finish: id=%d width=%d offset=%d factor=%x flags=%x request=%x config=%x\n", + dnegoprintk(("Finish: id=%d width=%d offset=%d factor=%x negoFlags=%x request=%x config=%x\n", id, width, offset, factor, dv->now.flags, val, configuration)); - pPage1->RequestedParameters = le32_to_cpu(val); + pPage1->RequestedParameters = cpu_to_le32(val); pPage1->Reserved = 0; - pPage1->Configuration = le32_to_cpu(configuration); + pPage1->Configuration = cpu_to_le32(configuration); } ddvprintk(("Finish: id=%d offset=%d factor=%x width=%d request=%x config=%x\n", From c6678e0cfb41b029c3600c54b5bb65954de1230a Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 18 Aug 2005 16:24:53 +0200 Subject: [PATCH 092/114] [SCSI] fusion: whitespace fixes Acked by: Moore, Eric Dean Signed-off-by: James Bottomley --- drivers/message/fusion/mptbase.c | 225 ++++++++++++++++-------------- drivers/message/fusion/mptscsih.c | 98 +++++++------ drivers/message/fusion/mptspi.c | 6 +- 3 files changed, 174 insertions(+), 155 deletions(-) diff --git a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c index 35444ba4e78a..f517d0692d5f 100644 --- a/drivers/message/fusion/mptbase.c +++ b/drivers/message/fusion/mptbase.c @@ -218,8 +218,7 @@ pci_enable_io_access(struct pci_dev *pdev) * (also referred to as a IO Controller or IOC). * This routine must clear the interrupt from the adapter and does * so by reading the reply FIFO. Multiple replies may be processed - * per single call to this routine; up to MPT_MAX_REPLIES_PER_ISR - * which is currently set to 32 in mptbase.h. + * per single call to this routine. * * This routine handles register-level access of the adapter but * dispatches (calls) a protocol-specific callback routine to handle @@ -279,11 +278,11 @@ mpt_interrupt(int irq, void *bus_id, struct pt_regs *r) cb_idx = mr->u.frame.hwhdr.msgctxu.fld.cb_idx; mf = MPT_INDEX_2_MFPTR(ioc, req_idx); - dmfprintk((MYIOC_s_INFO_FMT "Got non-TURBO reply=%p req_idx=%x\n", - ioc->name, mr, req_idx)); + dmfprintk((MYIOC_s_INFO_FMT "Got non-TURBO reply=%p req_idx=%x cb_idx=%x Function=%x\n", + ioc->name, mr, req_idx, cb_idx, mr->u.hdr.Function)); DBG_DUMP_REPLY_FRAME(mr) - /* Check/log IOC log info + /* Check/log IOC log info */ ioc_stat = le16_to_cpu(mr->u.reply.IOCStatus); if (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE) { @@ -345,7 +344,7 @@ mpt_interrupt(int irq, void *bus_id, struct pt_regs *r) if ((mf) && ((mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth)) || (mf < ioc->req_frames)) ) { printk(MYIOC_s_WARN_FMT - "mpt_interrupt: Invalid mf (%p) req_idx (%d)!\n", ioc->name, (void *)mf, req_idx); + "mpt_interrupt: Invalid mf (%p)!\n", ioc->name, (void *)mf); cb_idx = 0; pa = 0; freeme = 0; @@ -399,7 +398,7 @@ mpt_interrupt(int irq, void *bus_id, struct pt_regs *r) * @mf: Pointer to original MPT request frame * @reply: Pointer to MPT reply frame (NULL if TurboReply) * - * Returns 1 indicating original alloc'd request frame ptr + * Returns 1 indicating original alloc'd request frame ptr * should be freed, or 0 if it shouldn't. */ static int @@ -408,28 +407,17 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply) int freereq = 1; u8 func; - dprintk((MYIOC_s_INFO_FMT "mpt_base_reply() called\n", ioc->name)); - - if ((mf == NULL) || - (mf >= MPT_INDEX_2_MFPTR(ioc, ioc->req_depth))) { - printk(MYIOC_s_ERR_FMT "NULL or BAD request frame ptr! (=%p)\n", - ioc->name, (void *)mf); - return 1; - } - - if (reply == NULL) { - dprintk((MYIOC_s_ERR_FMT "Unexpected NULL Event (turbo?) reply!\n", - ioc->name)); - return 1; - } + dmfprintk((MYIOC_s_INFO_FMT "mpt_base_reply() called\n", ioc->name)); +#if defined(MPT_DEBUG_MSG_FRAME) if (!(reply->u.hdr.MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY)) { dmfprintk((KERN_INFO MYNAM ": Original request frame (@%p) header\n", mf)); DBG_DUMP_REQUEST_FRAME_HDR(mf) } +#endif func = reply->u.hdr.Function; - dprintk((MYIOC_s_INFO_FMT "mpt_base_reply, Function=%02Xh\n", + dmfprintk((MYIOC_s_INFO_FMT "mpt_base_reply, Function=%02Xh\n", ioc->name, func)); if (func == MPI_FUNCTION_EVENT_NOTIFICATION) { @@ -448,8 +436,14 @@ mpt_base_reply(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *reply) * Hmmm... It seems that EventNotificationReply is an exception * to the rule of one reply per request. */ - if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) + if (pEvReply->MsgFlags & MPI_MSGFLAGS_CONTINUATION_REPLY) { freereq = 0; + devtprintk((MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p does not return Request frame\n", + ioc->name, pEvReply)); + } else { + devtprintk((MYIOC_s_WARN_FMT "EVENT_NOTIFICATION reply %p returns Request frame\n", + ioc->name, pEvReply)); + } #ifdef CONFIG_PROC_FS // LogEvent(ioc, pEvReply); @@ -716,7 +710,7 @@ mpt_device_driver_deregister(int cb_idx) if (dd_cbfunc->remove) dd_cbfunc->remove(ioc->pcidev); } - + MptDeviceDriverHandlers[cb_idx] = NULL; } @@ -829,7 +823,7 @@ mpt_put_msg_frame(int handle, MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf) } #endif - mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx]; + mf_dma_addr = (ioc->req_frames_low_dma + req_offset) | ioc->RequestNB[req_idx]; dsgprintk((MYIOC_s_INFO_FMT "mf_dma_addr=%x req_idx=%d RequestNB=%x\n", ioc->name, mf_dma_addr, req_idx, ioc->RequestNB[req_idx])); CHIPREG_WRITE32(&ioc->chip->RequestFifo, mf_dma_addr); } @@ -931,7 +925,7 @@ mpt_send_handshake_request(int handle, MPT_ADAPTER *ioc, int reqBytes, u32 *req, /* Make sure there are no doorbells */ CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); - + CHIPREG_WRITE32(&ioc->chip->Doorbell, ((MPI_FUNCTION_HANDSHAKE<name, ii)); + ioc->name, ii)); CHIPREG_WRITE32(&ioc->chip->IntStatus, 0); if ((r = WaitForDoorbellAck(ioc, 5, sleepFlag)) < 0) { return -2; } - + /* Send request via doorbell handshake */ req_as_bytes = (u8 *) req; for (ii = 0; ii < reqBytes/4; ii++) { @@ -999,9 +993,9 @@ mpt_verify_adapter(int iocid, MPT_ADAPTER **iocpp) if (ioc->id == iocid) { *iocpp =ioc; return iocid; - } + } } - + *iocpp = NULL; return -1; } @@ -1043,9 +1037,9 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) if (pci_enable_device(pdev)) return r; - + dinitprintk((KERN_WARNING MYNAM ": mpt_adapter_install\n")); - + if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) { dprintk((KERN_INFO MYNAM ": 64 BIT PCI BUS DMA ADDRESSING SUPPORTED\n")); @@ -1070,7 +1064,7 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) ioc->alloc_total = sizeof(MPT_ADAPTER); ioc->req_sz = MPT_DEFAULT_FRAME_SIZE; /* avoid div by zero! */ ioc->reply_sz = MPT_REPLY_FRAME_SIZE; - + ioc->pcidev = pdev; ioc->diagPending = 0; spin_lock_init(&ioc->diagLock); @@ -1099,7 +1093,7 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) /* Find lookup slot. */ INIT_LIST_HEAD(&ioc->list); ioc->id = mpt_ids++; - + mem_phys = msize = 0; port = psize = 0; for (ii=0; ii < DEVICE_COUNT_RESOURCE; ii++) { @@ -1154,7 +1148,7 @@ mpt_attach(struct pci_dev *pdev, const struct pci_device_id *id) ioc->prod_name = "LSIFC909"; ioc->bus_type = FC; } - if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) { + else if (pdev->device == MPI_MANUFACTPAGE_DEVICEID_FC929) { ioc->prod_name = "LSIFC929"; ioc->bus_type = FC; } @@ -1333,7 +1327,7 @@ mpt_detach(struct pci_dev *pdev) remove_proc_entry(pname, NULL); sprintf(pname, MPT_PROCFS_MPTBASEDIR "/%s", ioc->name); remove_proc_entry(pname, NULL); - + /* call per device driver remove entry point */ for(ii=0; iiremove(pdev); } } - + /* Disable interrupts! */ CHIPREG_WRITE32(&ioc->chip->IntMask, 0xFFFFFFFF); @@ -1414,7 +1408,7 @@ mpt_resume(struct pci_dev *pdev) u32 device_state = pdev->current_state; int recovery_state; int ii; - + printk(MYIOC_s_INFO_FMT "pci-resume: pdev=0x%p, slot=%s, Previous operating state [D%d]\n", ioc->name, pdev, pci_name(pdev), device_state); @@ -1545,7 +1539,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) if ((rc = GetIocFacts(ioc, sleepFlag, reason)) == 0) break; } - + if (ii == 5) { dinitprintk((MYIOC_s_INFO_FMT "Retry IocFacts failed rc=%x\n", ioc->name, rc)); @@ -1553,7 +1547,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) } else if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { MptDisplayIocCapabilities(ioc); } - + if (alt_ioc_ready) { if ((rc = GetIocFacts(ioc->alt_ioc, sleepFlag, reason)) != 0) { dinitprintk((MYIOC_s_INFO_FMT "Initial Alt IocFacts failed rc=%x\n", ioc->name, rc)); @@ -1624,7 +1618,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) if (reset_alt_ioc_active && ioc->alt_ioc) { /* (re)Enable alt-IOC! (reply interrupt) */ - dprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n", + dinitprintk((KERN_INFO MYNAM ": alt-%s reply irq re-enabled\n", ioc->alt_ioc->name)); CHIPREG_WRITE32(&ioc->alt_ioc->chip->IntMask, ~(MPI_HIM_RIM)); ioc->alt_ioc->active = 1; @@ -1681,7 +1675,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) /* Find IM volumes */ - if (ioc->facts.MsgVersion >= 0x0102) + if (ioc->facts.MsgVersion >= MPI_VERSION_01_02) mpt_findImVolumes(ioc); /* Check, and possibly reset, the coalescing value @@ -1711,7 +1705,7 @@ mpt_do_ioc_recovery(MPT_ADAPTER *ioc, u32 reason, int sleepFlag) } if (alt_ioc_ready && MptResetHandlers[ii]) { - dprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n", + drsprintk((MYIOC_s_INFO_FMT "Calling alt-%s post_reset handler #%d\n", ioc->name, ioc->alt_ioc->name, ii)); rc += (*(MptResetHandlers[ii]))(ioc->alt_ioc, MPT_IOC_POST_RESET); handlers++; @@ -1744,8 +1738,8 @@ mpt_detect_bound_ports(MPT_ADAPTER *ioc, struct pci_dev *pdev) dprintk((MYIOC_s_INFO_FMT "PCI device %s devfn=%x/%x," " searching for devfn match on %x or %x\n", - ioc->name, pci_name(pdev), pdev->devfn, - func-1, func+1)); + ioc->name, pci_name(pdev), pdev->bus->number, + pdev->devfn, func-1, func+1)); peer = pci_get_slot(pdev->bus, PCI_DEVFN(slot,func-1)); if (!peer) { @@ -1872,36 +1866,39 @@ mpt_adapter_disable(MPT_ADAPTER *ioc) static void mpt_adapter_dispose(MPT_ADAPTER *ioc) { - if (ioc != NULL) { - int sz_first, sz_last; + int sz_first, sz_last; - sz_first = ioc->alloc_total; + if (ioc == NULL) + return; - mpt_adapter_disable(ioc); + sz_first = ioc->alloc_total; - if (ioc->pci_irq != -1) { - free_irq(ioc->pci_irq, ioc); - ioc->pci_irq = -1; - } + mpt_adapter_disable(ioc); - if (ioc->memmap != NULL) - iounmap(ioc->memmap); + if (ioc->pci_irq != -1) { + free_irq(ioc->pci_irq, ioc); + ioc->pci_irq = -1; + } + + if (ioc->memmap != NULL) { + iounmap(ioc->memmap); + ioc->memmap = NULL; + } #if defined(CONFIG_MTRR) && 0 - if (ioc->mtrr_reg > 0) { - mtrr_del(ioc->mtrr_reg, 0, 0); - dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n", ioc->name)); - } + if (ioc->mtrr_reg > 0) { + mtrr_del(ioc->mtrr_reg, 0, 0); + dprintk((KERN_INFO MYNAM ": %s: MTRR region de-registered\n", ioc->name)); + } #endif - /* Zap the adapter lookup ptr! */ - list_del(&ioc->list); + /* Zap the adapter lookup ptr! */ + list_del(&ioc->list); - sz_last = ioc->alloc_total; - dprintk((KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n", - ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first)); - kfree(ioc); - } + sz_last = ioc->alloc_total; + dprintk((KERN_INFO MYNAM ": %s: free'd %d of %d bytes\n", + ioc->name, sz_first-sz_last+(int)sizeof(*ioc), sz_first)); + kfree(ioc); } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -1988,7 +1985,7 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag) } /* Is it already READY? */ - if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY) + if (!statefault && (ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_READY) return 0; /* @@ -2006,7 +2003,7 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag) * Hmmm... Did it get left operational? */ if ((ioc_state & MPI_IOC_STATE_MASK) == MPI_IOC_STATE_OPERATIONAL) { - dinitprintk((MYIOC_s_WARN_FMT "IOC operational unexpected\n", + dinitprintk((MYIOC_s_INFO_FMT "IOC operational unexpected\n", ioc->name)); /* Check WhoInit. @@ -2015,8 +2012,8 @@ MakeIocReady(MPT_ADAPTER *ioc, int force, int sleepFlag) * Else, fall through to KickStart case */ whoinit = (ioc_state & MPI_DOORBELL_WHO_INIT_MASK) >> MPI_DOORBELL_WHO_INIT_SHIFT; - dprintk((KERN_WARNING MYNAM - ": whoinit 0x%x\n statefault %d force %d\n", + dinitprintk((KERN_INFO MYNAM + ": whoinit 0x%x statefault %d force %d\n", whoinit, statefault, force)); if (whoinit == MPI_WHOINIT_PCI_PEER) return -4; @@ -2151,8 +2148,8 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason) get_facts.Function = MPI_FUNCTION_IOC_FACTS; /* Assert: All other get_facts fields are zero! */ - dinitprintk((MYIOC_s_INFO_FMT - "Sending get IocFacts request req_sz=%d reply_sz=%d\n", + dinitprintk((MYIOC_s_INFO_FMT + "Sending get IocFacts request req_sz=%d reply_sz=%d\n", ioc->name, req_sz, reply_sz)); /* No non-zero fields in the get_facts request are greater than @@ -2232,7 +2229,7 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason) if ( sz & 0x02 ) sz += 2; facts->FWImageSize = sz; - + if (!facts->RequestFrameSize) { /* Something is wrong! */ printk(MYIOC_s_ERR_FMT "IOC reported invalid 0 request size!\n", @@ -2251,7 +2248,7 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason) ioc->NBShiftFactor = shiftFactor; dinitprintk((MYIOC_s_INFO_FMT "NB_for_64_byte_frame=%x NBShiftFactor=%x BlockSize=%x\n", ioc->name, vv, shiftFactor, r)); - + if (reason == MPT_HOSTEVENT_IOC_BRINGUP) { /* * Set values for this IOC's request & reply frame sizes, @@ -2272,7 +2269,7 @@ GetIocFacts(MPT_ADAPTER *ioc, int sleepFlag, int reason) return r; } } else { - printk(MYIOC_s_ERR_FMT + printk(MYIOC_s_ERR_FMT "Invalid IOC facts reply, msgLength=%d offsetof=%zd!\n", ioc->name, facts->MsgLength, (offsetof(IOCFactsReply_t, RequestFrameSize)/sizeof(u32))); @@ -2424,9 +2421,11 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepFlag) dhsprintk((MYIOC_s_INFO_FMT "Sending PortEnable (req @ %p)\n", ioc->name, &ioc_init)); - - if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) + + if ((r = SendPortEnable(ioc, 0, sleepFlag)) != 0) { + printk(MYIOC_s_ERR_FMT "Sending PortEnable failed(%d)!\n",ioc->name, r); return r; + } /* YIKES! SUPER IMPORTANT!!! * Poll IocState until _OPERATIONAL while IOC is doing @@ -2451,7 +2450,7 @@ SendIocInit(MPT_ADAPTER *ioc, int sleepFlag) state = mpt_GetIocState(ioc, 1); count++; } - dhsprintk((MYIOC_s_INFO_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n", + dinitprintk((MYIOC_s_INFO_FMT "INFO - Wait IOC_OPERATIONAL state (cnt=%d)\n", ioc->name, count)); return r; @@ -2540,7 +2539,7 @@ mpt_free_fw_memory(MPT_ADAPTER *ioc) int sz; sz = ioc->facts.FWImageSize; - dinitprintk((KERN_WARNING MYNAM "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n", + dinitprintk((KERN_INFO MYNAM "free_fw_memory: FW Image @ %p[%p], sz=%d[%x] bytes\n", ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz)); pci_free_consistent(ioc->pcidev, sz, ioc->cached_fw, ioc->cached_fw_dma); @@ -2584,9 +2583,9 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag) mpt_alloc_fw_memory(ioc, sz); - dinitprintk((KERN_WARNING MYNAM ": FW Image @ %p[%p], sz=%d[%x] bytes\n", + dinitprintk((KERN_INFO MYNAM ": FW Image @ %p[%p], sz=%d[%x] bytes\n", ioc->cached_fw, (void *)(ulong)ioc->cached_fw_dma, sz, sz)); - + if (ioc->cached_fw == NULL) { /* Major Failure. */ @@ -2616,14 +2615,14 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag) mpt_add_sge(&request[sgeoffset], flagsLength, ioc->cached_fw_dma); sgeoffset += sizeof(u32) + sizeof(dma_addr_t); - dinitprintk((KERN_WARNING MYNAM "Sending FW Upload (req @ %p) sgeoffset=%d \n", + dinitprintk((KERN_INFO MYNAM ": Sending FW Upload (req @ %p) sgeoffset=%d \n", prequest, sgeoffset)); DBG_DUMP_FW_REQUEST_FRAME(prequest) ii = mpt_handshake_req_reply_wait(ioc, sgeoffset, (u32*)prequest, reply_sz, (u16*)preply, 65 /*seconds*/, sleepFlag); - dinitprintk((KERN_WARNING MYNAM "FW Upload completed rc=%x \n", ii)); + dinitprintk((KERN_INFO MYNAM ": FW Upload completed rc=%x \n", ii)); cmdStatus = -EFAULT; if (ii == 0) { @@ -2638,10 +2637,10 @@ mpt_do_upload(MPT_ADAPTER *ioc, int sleepFlag) cmdStatus = 0; } } - dinitprintk((MYIOC_s_INFO_FMT ": do_upload status %d \n", + dinitprintk((MYIOC_s_INFO_FMT ": do_upload cmdStatus=%d \n", ioc->name, cmdStatus)); - + if (cmdStatus) { ddlprintk((MYIOC_s_INFO_FMT ": fw upload failed, freeing image \n", @@ -2772,8 +2771,8 @@ mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag) fwSize = (pExtImage->ImageSize + 3) >> 2; ptrFw = (u32 *)pExtImage; - ddlprintk((MYIOC_s_INFO_FMT "Write Ext Image: 0x%x bytes @ %p load_addr=%x\n", - ioc->name, fwSize*4, ptrFw, load_addr)); + ddlprintk((MYIOC_s_INFO_FMT "Write Ext Image: 0x%x (%d) bytes @ %p load_addr=%x\n", + ioc->name, fwSize*4, fwSize*4, ptrFw, load_addr)); CHIPREG_PIO_WRITE32(&ioc->pio_chip->DiagRwAddress, load_addr); while (fwSize--) { @@ -2856,9 +2855,9 @@ mpt_downloadboot(MPT_ADAPTER *ioc, int sleepFlag) * 0 else * * Returns: - * 1 - hard reset, READY - * 0 - no reset due to History bit, READY - * -1 - no reset due to History bit but not READY + * 1 - hard reset, READY + * 0 - no reset due to History bit, READY + * -1 - no reset due to History bit but not READY * OR reset but failed to come READY * -2 - no reset, could not enter DIAG mode * -3 - reset but bad FW bit @@ -3001,7 +3000,7 @@ mpt_diag_reset(MPT_ADAPTER *ioc, int ignore, int sleepFlag) * */ CHIPREG_WRITE32(&ioc->chip->Diagnostic, diag0val | MPI_DIAG_DISABLE_ARM); - mdelay (1); + mdelay(1); /* * Now hit the reset bit in the Diagnostic register @@ -3181,7 +3180,7 @@ SendIocReset(MPT_ADAPTER *ioc, u8 reset_type, int sleepFlag) u32 state; int cntdn, count; - drsprintk((KERN_WARNING MYNAM ": %s: Sending IOC reset(0x%02x)!\n", + drsprintk((KERN_INFO MYNAM ": %s: Sending IOC reset(0x%02x)!\n", ioc->name, reset_type)); CHIPREG_WRITE32(&ioc->chip->Doorbell, reset_type<reply_frames = (MPT_FRAME_HDR *) mem; ioc->reply_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF); + dinitprintk((KERN_INFO MYNAM ": %s ReplyBuffers @ %p[%p]\n", + ioc->name, ioc->reply_frames, (void *)(ulong)alloc_dma)); + alloc_dma += reply_sz; mem += reply_sz; @@ -3393,7 +3395,7 @@ PrimeIocFifos(MPT_ADAPTER *ioc) ioc->req_frames = (MPT_FRAME_HDR *) mem; ioc->req_frames_dma = alloc_dma; - dinitprintk((KERN_INFO MYNAM ": %s.RequestBuffers @ %p[%p]\n", + dinitprintk((KERN_INFO MYNAM ": %s RequestBuffers @ %p[%p]\n", ioc->name, mem, (void *)(ulong)alloc_dma)); ioc->req_frames_low_dma = (u32) (alloc_dma & 0xFFFFFFFF); @@ -3419,7 +3421,7 @@ PrimeIocFifos(MPT_ADAPTER *ioc) ioc->ChainBuffer = mem; ioc->ChainBufferDMA = alloc_dma; - dinitprintk((KERN_INFO MYNAM " :%s.ChainBuffers @ %p(%p)\n", + dinitprintk((KERN_INFO MYNAM " :%s ChainBuffers @ %p(%p)\n", ioc->name, ioc->ChainBuffer, (void *)(ulong)ioc->ChainBufferDMA)); /* Initialize the free chain Q. @@ -3524,7 +3526,7 @@ PrimeIocFifos(MPT_ADAPTER *ioc) */ static int mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req, - int replyBytes, u16 *u16reply, int maxwait, int sleepFlag) + int replyBytes, u16 *u16reply, int maxwait, int sleepFlag) { MPIDefaultReply_t *mptReply; int failcnt = 0; @@ -3599,7 +3601,7 @@ mpt_handshake_req_reply_wait(MPT_ADAPTER *ioc, int reqBytes, u32 *req, */ if (!failcnt && (t = WaitForDoorbellReply(ioc, maxwait, sleepFlag)) < 0) failcnt++; - + dhsprintk((MYIOC_s_INFO_FMT "HandShake reply count=%d%s\n", ioc->name, t, failcnt ? " - MISSING DOORBELL REPLY!" : "")); @@ -3758,7 +3760,7 @@ WaitForDoorbellReply(MPT_ADAPTER *ioc, int howlong, int sleepFlag) } dhsprintk((MYIOC_s_INFO_FMT "WaitCnt=%d First handshake reply word=%08x%s\n", - ioc->name, t, le32_to_cpu(*(u32 *)hs_reply), + ioc->name, t, le32_to_cpu(*(u32 *)hs_reply), failcnt ? " - MISSING DOORBELL HANDSHAKE!" : "")); /* @@ -4133,6 +4135,8 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum) ioc->spi_data.minSyncFactor = MPT_ASYNC; ioc->spi_data.busType = MPT_HOST_BUS_UNKNOWN; rc = 1; + ddvprintk((MYIOC_s_INFO_FMT "Unable to read PortPage0 minSyncFactor=%x\n", + ioc->name, ioc->spi_data.minSyncFactor)); } else { /* Save the Port Page 0 data */ @@ -4142,7 +4146,7 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum) if ( (pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_QAS) == 0 ) { ioc->spi_data.noQas |= MPT_TARGET_NO_NEGO_QAS; - dinitprintk((KERN_INFO MYNAM " :%s noQas due to Capabilities=%x\n", + ddvprintk((KERN_INFO MYNAM " :%s noQas due to Capabilities=%x\n", ioc->name, pPP0->Capabilities)); } ioc->spi_data.maxBusWidth = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_WIDE ? 1 : 0; @@ -4151,6 +4155,8 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum) ioc->spi_data.maxSyncOffset = (u8) (data >> 16); data = pPP0->Capabilities & MPI_SCSIPORTPAGE0_CAP_MIN_SYNC_PERIOD_MASK; ioc->spi_data.minSyncFactor = (u8) (data >> 8); + ddvprintk((MYIOC_s_INFO_FMT "PortPage0 minSyncFactor=%x\n", + ioc->name, ioc->spi_data.minSyncFactor)); } else { ioc->spi_data.maxSyncOffset = 0; ioc->spi_data.minSyncFactor = MPT_ASYNC; @@ -4163,8 +4169,11 @@ mpt_GetScsiPortSettings(MPT_ADAPTER *ioc, int portnum) if ((ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_HVD) || (ioc->spi_data.busType == MPI_SCSIPORTPAGE0_PHY_SIGNAL_SE)) { - if (ioc->spi_data.minSyncFactor < MPT_ULTRA) + if (ioc->spi_data.minSyncFactor < MPT_ULTRA) { ioc->spi_data.minSyncFactor = MPT_ULTRA; + ddvprintk((MYIOC_s_INFO_FMT "HVD or SE detected, minSyncFactor=%x\n", + ioc->name, ioc->spi_data.minSyncFactor)); + } } } if (pbuf) { @@ -4591,13 +4600,13 @@ SendEventNotification(MPT_ADAPTER *ioc, u8 EvSwitch) evnp = (EventNotification_t *) mpt_get_msg_frame(mpt_base_index, ioc); if (evnp == NULL) { - dprintk((MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n", + devtprintk((MYIOC_s_WARN_FMT "Unable to allocate event request frame!\n", ioc->name)); return 0; } memset(evnp, 0, sizeof(*evnp)); - dprintk((MYIOC_s_INFO_FMT "Sending EventNotification(%d)\n", ioc->name, EvSwitch)); + devtprintk((MYIOC_s_INFO_FMT "Sending EventNotification (%d) request %p\n", ioc->name, EvSwitch, evnp)); evnp->Function = MPI_FUNCTION_EVENT_NOTIFICATION; evnp->ChainOffset = 0; @@ -4621,8 +4630,10 @@ SendEventAck(MPT_ADAPTER *ioc, EventNotificationReply_t *evnp) EventAck_t *pAck; if ((pAck = (EventAck_t *) mpt_get_msg_frame(mpt_base_index, ioc)) == NULL) { - printk(MYIOC_s_WARN_FMT "Unable to allocate event ACK request frame!\n", - ioc->name); + printk(MYIOC_s_WARN_FMT "Unable to allocate event ACK " + "request frame for Event=%x EventContext=%x EventData=%x!\n", + ioc->name, evnp->Event, le32_to_cpu(evnp->EventContext), + le32_to_cpu(evnp->Data[0])); return -1; } memset(pAck, 0, sizeof(*pAck)); @@ -5538,6 +5549,8 @@ ProcessEventNotification(MPT_ADAPTER *ioc, EventNotificationReply_t *pEventReply * If needed, send (a single) EventAck. */ if (pEventReply->AckRequired == MPI_EVENT_NOTIFICATION_ACK_REQUIRED) { + devtprintk((MYIOC_s_WARN_FMT + "EventAck required\n",ioc->name)); if ((ii = SendEventAck(ioc, pEventReply)) != 0) { devtprintk((MYIOC_s_WARN_FMT "SendEventAck returned %d\n", ioc->name, ii)); @@ -5618,7 +5631,7 @@ mpt_sp_log_info(MPT_ADAPTER *ioc, u32 log_info) case 0x00080000: desc = "Outbound DMA Overrun"; break; - + case 0x00090000: desc = "Task Management"; break; @@ -5634,7 +5647,7 @@ mpt_sp_log_info(MPT_ADAPTER *ioc, u32 log_info) case 0x000C0000: desc = "Untagged Table Size"; break; - + } printk(MYIOC_s_INFO_FMT "LogInfo(0x%08x): F/W: %s\n", ioc->name, log_info, desc); @@ -5726,7 +5739,7 @@ mpt_sp_ioc_info(MPT_ADAPTER *ioc, u32 ioc_status, MPT_FRAME_HDR *mf) break; case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */ - /* This error is checked in scsi_io_done(). Skip. + /* This error is checked in scsi_io_done(). Skip. desc = "SCSI Data Underrun"; */ break; diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c index cd4e8c0853d0..4a003dc5fde8 100644 --- a/drivers/message/fusion/mptscsih.c +++ b/drivers/message/fusion/mptscsih.c @@ -281,12 +281,12 @@ mptscsih_getFreeChainBuffer(MPT_ADAPTER *ioc, int *retIndex) offset = (u8 *)chainBuf - (u8 *)ioc->ChainBuffer; chain_idx = offset / ioc->req_sz; rc = SUCCESS; - dsgprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer (index %d), got buf=%p\n", - ioc->name, *retIndex, chainBuf)); + dsgprintk((MYIOC_s_ERR_FMT "getFreeChainBuffer chainBuf=%p ChainBuffer=%p offset=%d chain_idx=%d\n", + ioc->name, chainBuf, ioc->ChainBuffer, offset, chain_idx)); } else { rc = FAILED; chain_idx = MPT_HOST_NO_CHAIN; - dfailprintk((MYIOC_s_ERR_FMT "getFreeChainBuffer failed\n", + dfailprintk((MYIOC_s_INFO_FMT "getFreeChainBuffer failed\n", ioc->name)); } spin_unlock_irqrestore(&ioc->FreeQlock, flags); @@ -432,7 +432,7 @@ mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt, */ pReq->ChainOffset = 0; RequestNB = (((sgeOffset - 1) >> ioc->NBShiftFactor) + 1) & 0x03; - dsgprintk((MYIOC_s_ERR_FMT + dsgprintk((MYIOC_s_INFO_FMT "Single Buffer RequestNB=%x, sgeOffset=%d\n", ioc->name, RequestNB, sgeOffset)); ioc->RequestNB[req_idx] = RequestNB; } @@ -491,11 +491,12 @@ mptscsih_AddSGE(MPT_ADAPTER *ioc, struct scsi_cmnd *SCpnt, /* NOTE: psge points to the beginning of the chain element * in current buffer. Get a chain buffer. */ - dsgprintk((MYIOC_s_INFO_FMT - "calling getFreeChainBuffer SCSI cmd=%02x (%p)\n", - ioc->name, pReq->CDB[0], SCpnt)); - if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) + if ((mptscsih_getFreeChainBuffer(ioc, &newIndex)) == FAILED) { + dfailprintk((MYIOC_s_INFO_FMT + "getFreeChainBuffer FAILED SCSI cmd=%02x (%p)\n", + ioc->name, pReq->CDB[0], SCpnt)); return FAILED; + } /* Update the tracking arrays. * If chainSge == NULL, update ReqToChain, else ChainToChain @@ -577,14 +578,20 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) return 1; } - dmfprintk((MYIOC_s_INFO_FMT - "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n", - ioc->name, mf, mr, sc, req_idx)); - sc->result = DID_OK << 16; /* Set default reply as OK */ pScsiReq = (SCSIIORequest_t *) mf; pScsiReply = (SCSIIOReply_t *) mr; + if((ioc->facts.MsgVersion >= MPI_VERSION_01_05) && pScsiReply){ + dmfprintk((MYIOC_s_INFO_FMT + "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d,task-tag=%d)\n", + ioc->name, mf, mr, sc, req_idx, pScsiReply->TaskTag)); + }else{ + dmfprintk((MYIOC_s_INFO_FMT + "ScsiDone (mf=%p,mr=%p,sc=%p,idx=%d)\n", + ioc->name, mf, mr, sc, req_idx)); + } + if (pScsiReply == NULL) { /* special context reply handling */ ; @@ -658,8 +665,8 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) /* Sufficient data transfer occurred */ sc->result = (DID_OK << 16) | scsi_status; } else if ( xfer_cnt == 0 ) { - /* A CRC Error causes this condition; retry */ - sc->result = (DRIVER_SENSE << 24) | (DID_OK << 16) | + /* A CRC Error causes this condition; retry */ + sc->result = (DRIVER_SENSE << 24) | (DID_OK << 16) | (CHECK_CONDITION << 1); sc->sense_buffer[0] = 0x70; sc->sense_buffer[2] = NO_SENSE; @@ -668,7 +675,9 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) } else { sc->result = DID_SOFT_ERROR << 16; } - dreplyprintk((KERN_NOTICE "RESIDUAL_MISMATCH: result=%x on id=%d\n", sc->result, sc->target)); + dreplyprintk((KERN_NOTICE + "RESIDUAL_MISMATCH: result=%x on id=%d\n", + sc->result, sc->device->id)); break; case MPI_IOCSTATUS_SCSI_DATA_UNDERRUN: /* 0x0045 */ @@ -796,7 +805,6 @@ mptscsih_io_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr) return 1; } - /* * mptscsih_flush_running_cmds - For each command found, search * Scsi_Host instance taskQ and reply to OS. @@ -1017,7 +1025,7 @@ mptscsih_remove(struct pci_dev *pdev) scsi_host_put(host); mpt_detach(pdev); - + } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ @@ -1072,7 +1080,7 @@ mptscsih_resume(struct pci_dev *pdev) MPT_SCSI_HOST *hd; mpt_resume(pdev); - + if(!host) return 0; @@ -1214,8 +1222,8 @@ mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t off int size = 0; if (func) { - /* - * write is not supported + /* + * write is not supported */ } else { if (start) @@ -1535,17 +1543,17 @@ mptscsih_TMHandler(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun, in */ if (mptscsih_tm_pending_wait(hd) == FAILED) { if (type == MPI_SCSITASKMGMT_TASKTYPE_ABORT_TASK) { - dtmprintk((KERN_WARNING MYNAM ": %s: TMHandler abort: " + dtmprintk((KERN_INFO MYNAM ": %s: TMHandler abort: " "Timed out waiting for last TM (%d) to complete! \n", hd->ioc->name, hd->tmPending)); return FAILED; } else if (type == MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET) { - dtmprintk((KERN_WARNING MYNAM ": %s: TMHandler target reset: " + dtmprintk((KERN_INFO MYNAM ": %s: TMHandler target reset: " "Timed out waiting for last TM (%d) to complete! \n", hd->ioc->name, hd->tmPending)); return FAILED; } else if (type == MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS) { - dtmprintk((KERN_WARNING MYNAM ": %s: TMHandler bus reset: " + dtmprintk((KERN_INFO MYNAM ": %s: TMHandler bus reset: " "Timed out waiting for last TM (%d) to complete! \n", hd->ioc->name, hd->tmPending)); if (hd->tmPending & (1 << MPI_SCSITASKMGMT_TASKTYPE_RESET_BUS)) @@ -1631,8 +1639,7 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun if ((mf = mpt_get_msg_frame(hd->ioc->TaskCtx, hd->ioc)) == NULL) { dfailprintk((MYIOC_s_ERR_FMT "IssueTaskMgmt, no msg frames!!\n", hd->ioc->name)); - //return FAILED; - return -999; + return FAILED; } dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt request @ %p\n", hd->ioc->name, mf)); @@ -1661,9 +1668,8 @@ mptscsih_IssueTaskMgmt(MPT_SCSI_HOST *hd, u8 type, u8 channel, u8 target, u8 lun pScsiTm->TaskMsgContext = ctx2abort; - dtmprintk((MYIOC_s_INFO_FMT - "IssueTaskMgmt: ctx2abort (0x%08x) type=%d\n", - hd->ioc->name, ctx2abort, type)); + dtmprintk((MYIOC_s_INFO_FMT "IssueTaskMgmt: ctx2abort (0x%08x) type=%d\n", + hd->ioc->name, ctx2abort, type)); DBG_DUMP_TM_REQUEST_FRAME((u32 *)pScsiTm); @@ -1902,13 +1908,13 @@ mptscsih_host_reset(struct scsi_cmnd *SCpnt) /* If we can't locate the host to reset, then we failed. */ if ((hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata) == NULL){ - dtmprintk( ( KERN_WARNING MYNAM ": mptscsih_host_reset: " + dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: " "Can't locate host! (sc=%p)\n", SCpnt ) ); return FAILED; } - printk(KERN_WARNING MYNAM ": %s: >> Attempting host reset! (sc=%p)\n", + printk(KERN_WARNING MYNAM ": %s: Attempting host reset! (sc=%p)\n", hd->ioc->name, SCpnt); /* If our attempts to reset the host failed, then return a failed @@ -1924,7 +1930,7 @@ mptscsih_host_reset(struct scsi_cmnd *SCpnt) hd->tmState = TM_STATE_NONE; } - dtmprintk( ( KERN_WARNING MYNAM ": mptscsih_host_reset: " + dtmprintk( ( KERN_INFO MYNAM ": mptscsih_host_reset: " "Status = %s\n", (status == SUCCESS) ? "SUCCESS" : "FAILED" ) ); @@ -1951,8 +1957,8 @@ mptscsih_tm_pending_wait(MPT_SCSI_HOST * hd) if (hd->tmState == TM_STATE_NONE) { hd->tmState = TM_STATE_IN_PROGRESS; hd->tmPending = 1; - status = SUCCESS; spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); + status = SUCCESS; break; } spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); @@ -1980,7 +1986,7 @@ mptscsih_tm_wait_for_completion(MPT_SCSI_HOST * hd, ulong timeout ) spin_lock_irqsave(&hd->ioc->FreeQlock, flags); if(hd->tmPending == 0) { status = SUCCESS; - spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); + spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); break; } spin_unlock_irqrestore(&hd->ioc->FreeQlock, flags); @@ -2318,10 +2324,10 @@ mptscsih_slave_configure(struct scsi_device *device) if (pTarget == NULL) { /* Driver doesn't know about this device. * Kernel may generate a "Dummy Lun 0" which - * may become a real Lun if a + * may become a real Lun if a * "scsi add-single-device" command is executed - * while the driver is active (hot-plug a - * device). LSI Raid controllers need + * while the driver is active (hot-plug a + * device). LSI Raid controllers need * queue_depth set to DEV_HIGH for this reason. */ scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG, @@ -2691,7 +2697,7 @@ mptscsih_initTarget(MPT_SCSI_HOST *hd, int bus_id, int target_id, u8 lun, char * * If the peripheral qualifier filter is enabled then if the target reports a 0x1 * (i.e. The targer is capable of supporting the specified peripheral device type * on this logical unit; however, the physical device is not currently connected - * to this logical unit) it will be converted to a 0x3 (i.e. The target is not + * to this logical unit) it will be converted to a 0x3 (i.e. The target is not * capable of supporting a physical device on this logical unit). This is to work * around a bug in th emid-layer in some distributions in which the mid-layer will * continue to try to communicate to the LUN and evntually create a dummy LUN. @@ -3194,8 +3200,8 @@ mptscsih_writeSDP1(MPT_SCSI_HOST *hd, int portnum, int target_id, int flags) /* Get a MF for this command. */ if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) { - dprintk((MYIOC_s_WARN_FMT "write SDP1: no msg frames!\n", - ioc->name)); + dfailprintk((MYIOC_s_WARN_FMT "write SDP1: no msg frames!\n", + ioc->name)); return -EAGAIN; } @@ -3289,7 +3295,7 @@ mptscsih_writeIOCPage4(MPT_SCSI_HOST *hd, int target_id, int bus) /* Get a MF for this command. */ if ((mf = mpt_get_msg_frame(ioc->DoneCtx, ioc)) == NULL) { - dprintk((MYIOC_s_WARN_FMT "writeIOCPage4 : no msg frames!\n", + dfailprintk((MYIOC_s_WARN_FMT "writeIOCPage4 : no msg frames!\n", ioc->name)); return -EAGAIN; } @@ -4596,8 +4602,8 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) if ((pbuf1[56] & 0x02) == 0) { pTarget->negoFlags |= MPT_TARGET_NO_NEGO_QAS; hd->ioc->spi_data.noQas = MPT_TARGET_NO_NEGO_QAS; - ddvprintk((MYIOC_s_NOTE_FMT - "DV: Start Basic noQas on id=%d due to pbuf1[56]=%x\n", + ddvprintk((MYIOC_s_NOTE_FMT + "DV: Start Basic noQas on id=%d due to pbuf1[56]=%x\n", ioc->name, id, pbuf1[56])); } } @@ -4673,7 +4679,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) if (!firstPass) doFallback = 1; } else { - ddvprintk((MYIOC_s_NOTE_FMT + ddvprintk((MYIOC_s_NOTE_FMT "DV:Inquiry compared id=%d, calling initTarget\n", ioc->name, id)); hd->ioc->spi_data.dvStatus[id] &= ~MPT_SCSICFG_DV_NOT_DONE; mptscsih_initTarget(hd, @@ -4689,8 +4695,8 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) } else if (rc == MPT_SCANDV_ISSUE_SENSE) doFallback = 1; /* set fallback flag */ - else if ((rc == MPT_SCANDV_DID_RESET) || - (rc == MPT_SCANDV_SENSE) || + else if ((rc == MPT_SCANDV_DID_RESET) || + (rc == MPT_SCANDV_SENSE) || (rc == MPT_SCANDV_FALLBACK)) doFallback = 1; /* set fallback flag */ else @@ -5126,7 +5132,7 @@ mptscsih_doDv(MPT_SCSI_HOST *hd, int bus_number, int id) */ if ((inq0 == 0) && (dv.now.factor > MPT_ULTRA320)) { hd->ioc->spi_data.noQas = MPT_TARGET_NO_NEGO_QAS; - ddvprintk((MYIOC_s_NOTE_FMT + ddvprintk((MYIOC_s_NOTE_FMT "noQas set due to id=%d has factor=%x\n", ioc->name, id, dv.now.factor)); } diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c index dfa8806b1e13..587d1274fd74 100644 --- a/drivers/message/fusion/mptspi.c +++ b/drivers/message/fusion/mptspi.c @@ -162,15 +162,15 @@ mptspi_probe(struct pci_dev *pdev, const struct pci_device_id *id) u8 *mem; int error=0; int r; - + if ((r = mpt_attach(pdev,id)) != 0) return r; - + ioc = pci_get_drvdata(pdev); ioc->DoneCtx = mptspiDoneCtx; ioc->TaskCtx = mptspiTaskCtx; ioc->InternalCtx = mptspiInternalCtx; - + /* Added sanity check on readiness of the MPT adapter. */ if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) { From 7524f9b9e72cd36f0a70defcd424eba81c180f42 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 26 Aug 2005 19:08:00 -0700 Subject: [PATCH 093/114] [SCSI] qla2xxx: Use dma_get_required_mask() in determining the 'ideal' DMA mask. In order to efficiently utilise the ISP's IOCB request-queue, use the dma_get_required_mask() function to determine the use of command-type 2 or 3 IOCBs when queueing SCSI commands. This applies to ISP2[123]xx chips only, as the ISP24xx uses command-type 7 IOCBs which use 64bit DSDs. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_os.c | 33 ++++++++++----------------------- 1 file changed, 10 insertions(+), 23 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 9000659bfbcf..995e521b07de 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1113,36 +1113,23 @@ qla2xxx_slave_destroy(struct scsi_device *sdev) static void qla2x00_config_dma_addressing(scsi_qla_host_t *ha) { - /* Assume 32bit DMA address */ + /* Assume a 32bit DMA mask. */ ha->flags.enable_64bit_addressing = 0; - /* - * Given the two variants pci_set_dma_mask(), allow the compiler to - * assist in setting the proper dma mask. - */ - if (sizeof(dma_addr_t) > 4) { - if (pci_set_dma_mask(ha->pdev, DMA_64BIT_MASK) == 0) { + if (!dma_set_mask(&ha->pdev->dev, DMA_64BIT_MASK)) { + /* Any upper-dword bits set? */ + if (MSD(dma_get_required_mask(&ha->pdev->dev)) && + !pci_set_consistent_dma_mask(ha->pdev, DMA_64BIT_MASK)) { + /* Ok, a 64bit DMA mask is applicable. */ ha->flags.enable_64bit_addressing = 1; ha->isp_ops.calc_req_entries = qla2x00_calc_iocbs_64; ha->isp_ops.build_iocbs = qla2x00_build_scsi_iocbs_64; - - if (pci_set_consistent_dma_mask(ha->pdev, - DMA_64BIT_MASK)) { - qla_printk(KERN_DEBUG, ha, - "Failed to set 64 bit PCI consistent mask; " - "using 32 bit.\n"); - pci_set_consistent_dma_mask(ha->pdev, - DMA_32BIT_MASK); - } - } else { - qla_printk(KERN_DEBUG, ha, - "Failed to set 64 bit PCI DMA mask, falling back " - "to 32 bit MASK.\n"); - pci_set_dma_mask(ha->pdev, DMA_32BIT_MASK); + return; } - } else { - pci_set_dma_mask(ha->pdev, DMA_32BIT_MASK); } + + dma_set_mask(&ha->pdev->dev, DMA_32BIT_MASK); + pci_set_consistent_dma_mask(ha->pdev, DMA_32BIT_MASK); } static int From ad3e0edaceb9771be7ffbd7aa24fb444a7ed85bf Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 26 Aug 2005 19:08:10 -0700 Subject: [PATCH 094/114] [SCSI] qla2xxx: Export class-of-service (COS) information. Export COS information for the fc_host and fc_remote_port objects added by the driver. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_attr.c | 4 ++++ drivers/scsi/qla2xxx/qla_def.h | 1 + drivers/scsi/qla2xxx/qla_init.c | 7 +++++++ drivers/scsi/qla2xxx/qla_mbx.c | 14 ++++++++++++++ 4 files changed, 26 insertions(+) diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 659a5d63467d..d05280eecc60 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -304,10 +304,13 @@ struct fc_function_template qla2xxx_transport_functions = { .show_host_node_name = 1, .show_host_port_name = 1, + .show_host_supported_classes = 1, + .get_host_port_id = qla2x00_get_host_port_id, .show_host_port_id = 1, .dd_fcrport_size = sizeof(struct fc_port *), + .show_rport_supported_classes = 1, .get_starget_node_name = qla2x00_get_starget_node_name, .show_starget_node_name = 1, @@ -329,4 +332,5 @@ qla2x00_init_host_attr(scsi_qla_host_t *ha) be64_to_cpu(*(uint64_t *)ha->init_cb->node_name); fc_host_port_name(ha->host) = be64_to_cpu(*(uint64_t *)ha->init_cb->port_name); + fc_host_supported_classes(ha->host) = FC_COS_CLASS3; } diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 1c6d366f4fad..38848c38ad8d 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -1673,6 +1673,7 @@ typedef struct fc_port { uint8_t cur_path; /* current path id */ struct fc_rport *rport; + u32 supported_classes; } fc_port_t; /* diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index a6d2559217cd..09b23f70fd66 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1697,6 +1697,7 @@ qla2x00_alloc_fcport(scsi_qla_host_t *ha, int flags) fcport->iodesc_idx_sent = IODESC_INVALID_INDEX; atomic_set(&fcport->state, FCS_UNCONFIGURED); fcport->flags = FCF_RLC_SUPPORT; + fcport->supported_classes = FC_COS_UNSPECIFIED; return (fcport); } @@ -2075,6 +2076,7 @@ qla2x00_reg_remote_port(scsi_qla_host_t *ha, fc_port_t *fcport) return; } rport->dd_data = fcport; + rport->supported_classes = fcport->supported_classes; rport_ids.roles = FC_RPORT_ROLE_UNKNOWN; if (fcport->port_type == FCT_INITIATOR) @@ -2794,6 +2796,11 @@ qla2x00_fabric_login(scsi_qla_host_t *ha, fc_port_t *fcport, } } + if (mb[10] & BIT_0) + fcport->supported_classes |= FC_COS_CLASS2; + if (mb[10] & BIT_1) + fcport->supported_classes |= FC_COS_CLASS3; + rval = QLA_SUCCESS; break; } else if (mb[0] == MBS_LOOP_ID_USED) { diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 409ea0ac4032..774309a77c05 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -19,6 +19,7 @@ #include "qla_def.h" #include +#include static void qla2x00_mbx_sem_timeout(unsigned long data) @@ -1326,6 +1327,10 @@ qla2x00_get_port_database(scsi_qla_host_t *ha, fc_port_t *fcport, uint8_t opt) fcport->port_type = FCT_INITIATOR; else fcport->port_type = FCT_TARGET; + + /* Passback COS information. */ + fcport->supported_classes = (pd->options & BIT_4) ? + FC_COS_CLASS2: FC_COS_CLASS3; } gpd_error_out: @@ -1661,6 +1666,13 @@ qla24xx_login_fabric(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain, mb[1] |= BIT_1; } else mb[1] = BIT_0; + + /* Passback COS information. */ + mb[10] = 0; + if (lg->io_parameter[7] || lg->io_parameter[8]) + mb[10] |= BIT_0; /* Class 2. */ + if (lg->io_parameter[9] || lg->io_parameter[10]) + mb[10] |= BIT_1; /* Class 3. */ } dma_pool_free(ha->s_dma_pool, lg, lg_dma); @@ -1723,6 +1735,8 @@ qla2x00_login_fabric(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain, mb[2] = mcp->mb[2]; mb[6] = mcp->mb[6]; mb[7] = mcp->mb[7]; + /* COS retrieved from Get-Port-Database mailbox command. */ + mb[10] = 0; } if (rval != QLA_SUCCESS) { From cca5335caf2d19ef8bd6b833445d2c6ca652a89b Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 26 Aug 2005 19:08:30 -0700 Subject: [PATCH 095/114] [SCSI] qla2xxx: Add FDMI support. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_dbg.h | 7 + drivers/scsi/qla2xxx/qla_def.h | 151 ++++++++- drivers/scsi/qla2xxx/qla_gbl.h | 4 + drivers/scsi/qla2xxx/qla_gs.c | 564 ++++++++++++++++++++++++++++++++ drivers/scsi/qla2xxx/qla_init.c | 6 + drivers/scsi/qla2xxx/qla_isr.c | 2 + drivers/scsi/qla2xxx/qla_mbx.c | 2 +- drivers/scsi/qla2xxx/qla_os.c | 10 + 8 files changed, 741 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h index b8d90e97e017..9684e7a91fa9 100644 --- a/drivers/scsi/qla2xxx/qla_dbg.h +++ b/drivers/scsi/qla2xxx/qla_dbg.h @@ -81,6 +81,7 @@ #define DEBUG2_3_11(x) do {x;} while (0); #define DEBUG2_9_10(x) do {x;} while (0); #define DEBUG2_11(x) do {x;} while (0); +#define DEBUG2_13(x) do {x;} while (0); #else #define DEBUG2(x) do {} while (0); #endif @@ -169,8 +170,14 @@ #if defined(QL_DEBUG_LEVEL_13) #define DEBUG13(x) do {x;} while (0) +#if !defined(DEBUG2_13) +#define DEBUG2_13(x) do {x;} while(0) +#endif #else #define DEBUG13(x) do {} while (0) +#if !defined(QL_DEBUG_LEVEL_2) +#define DEBUG2_13(x) do {} while(0) +#endif #endif #if defined(QL_DEBUG_LEVEL_14) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 38848c38ad8d..cdef86e49c60 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -214,6 +214,7 @@ * valid range of an N-PORT id is 0 through 0x7ef. */ #define NPH_LAST_HANDLE 0x7ef +#define NPH_MGMT_SERVER 0x7fa /* FFFFFA */ #define NPH_SNS 0x7fc /* FFFFFC */ #define NPH_FABRIC_CONTROLLER 0x7fd /* FFFFFD */ #define NPH_F_PORT 0x7fe /* FFFFFE */ @@ -1131,10 +1132,7 @@ typedef struct { uint8_t link_down_timeout; - uint8_t adapter_id_0[4]; - uint8_t adapter_id_1[4]; - uint8_t adapter_id_2[4]; - uint8_t adapter_id_3[4]; + uint8_t adapter_id[16]; uint8_t alt1_boot_node_name[WWN_SIZE]; uint16_t alt1_boot_lun_number; @@ -1728,6 +1726,8 @@ typedef struct fc_port { #define CT_REJECT_RESPONSE 0x8001 #define CT_ACCEPT_RESPONSE 0x8002 +#define CT_REASON_CANNOT_PERFORM 0x09 +#define CT_EXPL_ALREADY_REGISTERED 0x10 #define NS_N_PORT_TYPE 0x01 #define NS_NL_PORT_TYPE 0x02 @@ -1769,6 +1769,100 @@ typedef struct fc_port { #define RSNN_NN_REQ_SIZE (16 + 8 + 1 + 255) #define RSNN_NN_RSP_SIZE 16 +/* + * HBA attribute types. + */ +#define FDMI_HBA_ATTR_COUNT 9 +#define FDMI_HBA_NODE_NAME 1 +#define FDMI_HBA_MANUFACTURER 2 +#define FDMI_HBA_SERIAL_NUMBER 3 +#define FDMI_HBA_MODEL 4 +#define FDMI_HBA_MODEL_DESCRIPTION 5 +#define FDMI_HBA_HARDWARE_VERSION 6 +#define FDMI_HBA_DRIVER_VERSION 7 +#define FDMI_HBA_OPTION_ROM_VERSION 8 +#define FDMI_HBA_FIRMWARE_VERSION 9 +#define FDMI_HBA_OS_NAME_AND_VERSION 0xa +#define FDMI_HBA_MAXIMUM_CT_PAYLOAD_LENGTH 0xb + +struct ct_fdmi_hba_attr { + uint16_t type; + uint16_t len; + union { + uint8_t node_name[WWN_SIZE]; + uint8_t manufacturer[32]; + uint8_t serial_num[8]; + uint8_t model[16]; + uint8_t model_desc[80]; + uint8_t hw_version[16]; + uint8_t driver_version[32]; + uint8_t orom_version[16]; + uint8_t fw_version[16]; + uint8_t os_version[128]; + uint8_t max_ct_len[4]; + } a; +}; + +struct ct_fdmi_hba_attributes { + uint32_t count; + struct ct_fdmi_hba_attr entry[FDMI_HBA_ATTR_COUNT]; +}; + +/* + * Port attribute types. + */ +#define FDMI_PORT_ATTR_COUNT 5 +#define FDMI_PORT_FC4_TYPES 1 +#define FDMI_PORT_SUPPORT_SPEED 2 +#define FDMI_PORT_CURRENT_SPEED 3 +#define FDMI_PORT_MAX_FRAME_SIZE 4 +#define FDMI_PORT_OS_DEVICE_NAME 5 +#define FDMI_PORT_HOST_NAME 6 + +struct ct_fdmi_port_attr { + uint16_t type; + uint16_t len; + union { + uint8_t fc4_types[32]; + uint32_t sup_speed; + uint32_t cur_speed; + uint32_t max_frame_size; + uint8_t os_dev_name[32]; + uint8_t host_name[32]; + } a; +}; + +/* + * Port Attribute Block. + */ +struct ct_fdmi_port_attributes { + uint32_t count; + struct ct_fdmi_port_attr entry[FDMI_PORT_ATTR_COUNT]; +}; + +/* FDMI definitions. */ +#define GRHL_CMD 0x100 +#define GHAT_CMD 0x101 +#define GRPL_CMD 0x102 +#define GPAT_CMD 0x110 + +#define RHBA_CMD 0x200 +#define RHBA_RSP_SIZE 16 + +#define RHAT_CMD 0x201 +#define RPRT_CMD 0x210 + +#define RPA_CMD 0x211 +#define RPA_RSP_SIZE 16 + +#define DHBA_CMD 0x300 +#define DHBA_REQ_SIZE (16 + 8) +#define DHBA_RSP_SIZE 16 + +#define DHAT_CMD 0x301 +#define DPRT_CMD 0x310 +#define DPA_CMD 0x311 + /* CT command header -- request/response common fields */ struct ct_cmd_hdr { uint8_t revision; @@ -1826,6 +1920,43 @@ struct ct_sns_req { uint8_t name_len; uint8_t sym_node_name[255]; } rsnn_nn; + + struct { + uint8_t hba_indentifier[8]; + } ghat; + + struct { + uint8_t hba_identifier[8]; + uint32_t entry_count; + uint8_t port_name[8]; + struct ct_fdmi_hba_attributes attrs; + } rhba; + + struct { + uint8_t hba_identifier[8]; + struct ct_fdmi_hba_attributes attrs; + } rhat; + + struct { + uint8_t port_name[8]; + struct ct_fdmi_port_attributes attrs; + } rpa; + + struct { + uint8_t port_name[8]; + } dhba; + + struct { + uint8_t port_name[8]; + } dhat; + + struct { + uint8_t port_name[8]; + } dprt; + + struct { + uint8_t port_name[8]; + } dpa; } req; }; @@ -1883,6 +2014,12 @@ struct ct_sns_rsp { struct { uint8_t fc4_types[32]; } gft_id; + + struct { + uint32_t entry_count; + uint8_t port_name[8]; + struct ct_fdmi_hba_attributes attrs; + } ghat; } rsp; }; @@ -2033,6 +2170,8 @@ struct isp_operations { uint16_t (*calc_req_entries) (uint16_t); void (*build_iocbs) (srb_t *, cmd_entry_t *, uint16_t); void * (*prep_ms_iocb) (struct scsi_qla_host *, uint32_t, uint32_t); + void * (*prep_ms_fdmi_iocb) (struct scsi_qla_host *, uint32_t, + uint32_t); uint8_t * (*read_nvram) (struct scsi_qla_host *, uint8_t *, uint32_t, uint32_t); @@ -2112,6 +2251,7 @@ typedef struct scsi_qla_host { #define IOCTL_ERROR_RECOVERY 23 #define LOOP_RESET_NEEDED 24 #define BEACON_BLINK_NEEDED 25 +#define REGISTER_FDMI_NEEDED 26 uint32_t device_flags; #define DFLG_LOCAL_DEVICES BIT_0 @@ -2205,6 +2345,7 @@ typedef struct scsi_qla_host { int port_down_retry_count; uint8_t mbx_count; uint16_t last_loop_id; + uint16_t mgmt_svr_loop_id; uint32_t login_retry_count; @@ -2319,6 +2460,7 @@ typedef struct scsi_qla_host { uint8_t model_number[16+1]; #define BINZERO "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" char *model_desc; + uint8_t adapter_id[16+1]; uint8_t *node_name; uint8_t *port_name; @@ -2378,6 +2520,7 @@ typedef struct scsi_qla_host { #define QLA_SUSPENDED 0x106 #define QLA_BUSY 0x107 #define QLA_RSCNS_HANDLED 0x108 +#define QLA_ALREADY_REGISTERED 0x109 /* * Stat info for all adpaters diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 665c203e0675..3e1e5fe850a0 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -79,6 +79,7 @@ extern int ql2xplogiabsentdevice; extern int ql2xenablezio; extern int ql2xintrdelaytimer; extern int ql2xloginretrycount; +extern int ql2xfdmienable; extern void qla2x00_sp_compl(scsi_qla_host_t *, srb_t *); @@ -269,6 +270,9 @@ extern int qla2x00_rft_id(scsi_qla_host_t *); extern int qla2x00_rff_id(scsi_qla_host_t *); extern int qla2x00_rnn_id(scsi_qla_host_t *); extern int qla2x00_rsnn_nn(scsi_qla_host_t *); +extern void *qla2x00_prep_ms_fdmi_iocb(scsi_qla_host_t *, uint32_t, uint32_t); +extern void *qla24xx_prep_ms_fdmi_iocb(scsi_qla_host_t *, uint32_t, uint32_t); +extern int qla2x00_fdmi_register(scsi_qla_host_t *); /* * Global Function Prototypes in qla_rscn.c source file. diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 31ce4f62da13..e7b138c2e339 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -1099,3 +1099,567 @@ qla2x00_sns_rnn_id(scsi_qla_host_t *ha) return (rval); } + +/** + * qla2x00_mgmt_svr_login() - Login to fabric Managment Service. + * @ha: HA context + * + * Returns 0 on success. + */ +static int +qla2x00_mgmt_svr_login(scsi_qla_host_t *ha) +{ + int ret; + uint16_t mb[MAILBOX_REGISTER_COUNT]; + + ret = QLA_SUCCESS; + if (ha->flags.management_server_logged_in) + return ret; + + ha->isp_ops.fabric_login(ha, ha->mgmt_svr_loop_id, 0xff, 0xff, 0xfa, + mb, BIT_1); + if (mb[0] != MBS_COMMAND_COMPLETE) { + DEBUG2_13(printk("%s(%ld): Failed MANAGEMENT_SERVER login: " + "loop_id=%x mb[0]=%x mb[1]=%x mb[2]=%x mb[6]=%x mb[7]=%x\n", + __func__, ha->host_no, ha->mgmt_svr_loop_id, mb[0], mb[1], + mb[2], mb[6], mb[7])); + ret = QLA_FUNCTION_FAILED; + } else + ha->flags.management_server_logged_in = 1; + + return ret; +} + +/** + * qla2x00_prep_ms_fdmi_iocb() - Prepare common MS IOCB fields for FDMI query. + * @ha: HA context + * @req_size: request size in bytes + * @rsp_size: response size in bytes + * + * Returns a pointer to the @ha's ms_iocb. + */ +void * +qla2x00_prep_ms_fdmi_iocb(scsi_qla_host_t *ha, uint32_t req_size, + uint32_t rsp_size) +{ + ms_iocb_entry_t *ms_pkt; + + ms_pkt = ha->ms_iocb; + memset(ms_pkt, 0, sizeof(ms_iocb_entry_t)); + + ms_pkt->entry_type = MS_IOCB_TYPE; + ms_pkt->entry_count = 1; + SET_TARGET_ID(ha, ms_pkt->loop_id, ha->mgmt_svr_loop_id); + ms_pkt->control_flags = __constant_cpu_to_le16(CF_READ | CF_HEAD_TAG); + ms_pkt->timeout = __constant_cpu_to_le16(59); + ms_pkt->cmd_dsd_count = __constant_cpu_to_le16(1); + ms_pkt->total_dsd_count = __constant_cpu_to_le16(2); + ms_pkt->rsp_bytecount = cpu_to_le32(rsp_size); + ms_pkt->req_bytecount = cpu_to_le32(req_size); + + ms_pkt->dseg_req_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma)); + ms_pkt->dseg_req_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma)); + ms_pkt->dseg_req_length = ms_pkt->req_bytecount; + + ms_pkt->dseg_rsp_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma)); + ms_pkt->dseg_rsp_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma)); + ms_pkt->dseg_rsp_length = ms_pkt->rsp_bytecount; + + return ms_pkt; +} + +/** + * qla24xx_prep_ms_fdmi_iocb() - Prepare common MS IOCB fields for FDMI query. + * @ha: HA context + * @req_size: request size in bytes + * @rsp_size: response size in bytes + * + * Returns a pointer to the @ha's ms_iocb. + */ +void * +qla24xx_prep_ms_fdmi_iocb(scsi_qla_host_t *ha, uint32_t req_size, + uint32_t rsp_size) +{ + struct ct_entry_24xx *ct_pkt; + + ct_pkt = (struct ct_entry_24xx *)ha->ms_iocb; + memset(ct_pkt, 0, sizeof(struct ct_entry_24xx)); + + ct_pkt->entry_type = CT_IOCB_TYPE; + ct_pkt->entry_count = 1; + ct_pkt->nport_handle = cpu_to_le16(ha->mgmt_svr_loop_id); + ct_pkt->timeout = __constant_cpu_to_le16(59); + ct_pkt->cmd_dsd_count = __constant_cpu_to_le16(1); + ct_pkt->rsp_dsd_count = __constant_cpu_to_le16(1); + ct_pkt->rsp_byte_count = cpu_to_le32(rsp_size); + ct_pkt->cmd_byte_count = cpu_to_le32(req_size); + + ct_pkt->dseg_0_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma)); + ct_pkt->dseg_0_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma)); + ct_pkt->dseg_0_len = ct_pkt->cmd_byte_count; + + ct_pkt->dseg_1_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma)); + ct_pkt->dseg_1_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma)); + ct_pkt->dseg_1_len = ct_pkt->rsp_byte_count; + + return ct_pkt; +} + +static inline ms_iocb_entry_t * +qla2x00_update_ms_fdmi_iocb(scsi_qla_host_t *ha, uint32_t req_size) +{ + ms_iocb_entry_t *ms_pkt = ha->ms_iocb; + struct ct_entry_24xx *ct_pkt = (struct ct_entry_24xx *)ha->ms_iocb; + + if (IS_QLA24XX(ha) || IS_QLA25XX(ha)) { + ct_pkt->cmd_byte_count = cpu_to_le32(req_size); + ct_pkt->dseg_0_len = ct_pkt->cmd_byte_count; + } else { + ms_pkt->req_bytecount = cpu_to_le32(req_size); + ms_pkt->dseg_req_length = ms_pkt->req_bytecount; + } + + return ms_pkt; +} + +/** + * qla2x00_prep_ct_req() - Prepare common CT request fields for SNS query. + * @ct_req: CT request buffer + * @cmd: GS command + * @rsp_size: response size in bytes + * + * Returns a pointer to the intitialized @ct_req. + */ +static inline struct ct_sns_req * +qla2x00_prep_ct_fdmi_req(struct ct_sns_req *ct_req, uint16_t cmd, + uint16_t rsp_size) +{ + memset(ct_req, 0, sizeof(struct ct_sns_pkt)); + + ct_req->header.revision = 0x01; + ct_req->header.gs_type = 0xFA; + ct_req->header.gs_subtype = 0x10; + ct_req->command = cpu_to_be16(cmd); + ct_req->max_rsp_size = cpu_to_be16((rsp_size - 16) / 4); + + return ct_req; +} + +/** + * qla2x00_fdmi_rhba() - + * @ha: HA context + * + * Returns 0 on success. + */ +static int +qla2x00_fdmi_rhba(scsi_qla_host_t *ha) +{ + int rval, alen; + uint32_t size, sn; + + ms_iocb_entry_t *ms_pkt; + struct ct_sns_req *ct_req; + struct ct_sns_rsp *ct_rsp; + uint8_t *entries; + struct ct_fdmi_hba_attr *eiter; + + /* Issue RHBA */ + /* Prepare common MS IOCB */ + /* Request size adjusted after CT preparation */ + ms_pkt = ha->isp_ops.prep_ms_fdmi_iocb(ha, 0, RHBA_RSP_SIZE); + + /* Prepare CT request */ + ct_req = qla2x00_prep_ct_fdmi_req(&ha->ct_sns->p.req, RHBA_CMD, + RHBA_RSP_SIZE); + ct_rsp = &ha->ct_sns->p.rsp; + + /* Prepare FDMI command arguments -- attribute block, attributes. */ + memcpy(ct_req->req.rhba.hba_identifier, ha->port_name, WWN_SIZE); + ct_req->req.rhba.entry_count = __constant_cpu_to_be32(1); + memcpy(ct_req->req.rhba.port_name, ha->port_name, WWN_SIZE); + size = 2 * WWN_SIZE + 4 + 4; + + /* Attributes */ + ct_req->req.rhba.attrs.count = + __constant_cpu_to_be32(FDMI_HBA_ATTR_COUNT); + entries = ct_req->req.rhba.hba_identifier; + + /* Nodename. */ + eiter = (struct ct_fdmi_hba_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_HBA_NODE_NAME); + eiter->len = __constant_cpu_to_be16(4 + WWN_SIZE); + memcpy(eiter->a.node_name, ha->node_name, WWN_SIZE); + size += 4 + WWN_SIZE; + + DEBUG13(printk("%s(%ld): NODENAME=%02x%02x%02x%02x%02x%02x%02x%02x.\n", + __func__, ha->host_no, + eiter->a.node_name[0], eiter->a.node_name[1], eiter->a.node_name[2], + eiter->a.node_name[3], eiter->a.node_name[4], eiter->a.node_name[5], + eiter->a.node_name[6], eiter->a.node_name[7])); + + /* Manufacturer. */ + eiter = (struct ct_fdmi_hba_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_HBA_MANUFACTURER); + strcpy(eiter->a.manufacturer, "QLogic Corporation"); + alen = strlen(eiter->a.manufacturer); + alen += (alen & 3) ? (4 - (alen & 3)) : 4; + eiter->len = cpu_to_be16(4 + alen); + size += 4 + alen; + + DEBUG13(printk("%s(%ld): MANUFACTURER=%s.\n", __func__, ha->host_no, + eiter->a.manufacturer)); + + /* Serial number. */ + eiter = (struct ct_fdmi_hba_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_HBA_SERIAL_NUMBER); + sn = ((ha->serial0 & 0x1f) << 16) | (ha->serial2 << 8) | ha->serial1; + sprintf(eiter->a.serial_num, "%c%05d", 'A' + sn / 100000, sn % 100000); + alen = strlen(eiter->a.serial_num); + alen += (alen & 3) ? (4 - (alen & 3)) : 4; + eiter->len = cpu_to_be16(4 + alen); + size += 4 + alen; + + DEBUG13(printk("%s(%ld): SERIALNO=%s.\n", __func__, ha->host_no, + eiter->a.serial_num)); + + /* Model name. */ + eiter = (struct ct_fdmi_hba_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_HBA_MODEL); + strcpy(eiter->a.model, ha->model_number); + alen = strlen(eiter->a.model); + alen += (alen & 3) ? (4 - (alen & 3)) : 4; + eiter->len = cpu_to_be16(4 + alen); + size += 4 + alen; + + DEBUG13(printk("%s(%ld): MODEL_NAME=%s.\n", __func__, ha->host_no, + eiter->a.model)); + + /* Model description. */ + eiter = (struct ct_fdmi_hba_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_HBA_MODEL_DESCRIPTION); + if (ha->model_desc) + strncpy(eiter->a.model_desc, ha->model_desc, 80); + alen = strlen(eiter->a.model_desc); + alen += (alen & 3) ? (4 - (alen & 3)) : 4; + eiter->len = cpu_to_be16(4 + alen); + size += 4 + alen; + + DEBUG13(printk("%s(%ld): MODEL_DESC=%s.\n", __func__, ha->host_no, + eiter->a.model_desc)); + + /* Hardware version. */ + eiter = (struct ct_fdmi_hba_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_HBA_HARDWARE_VERSION); + strcpy(eiter->a.hw_version, ha->adapter_id); + alen = strlen(eiter->a.hw_version); + alen += (alen & 3) ? (4 - (alen & 3)) : 4; + eiter->len = cpu_to_be16(4 + alen); + size += 4 + alen; + + DEBUG13(printk("%s(%ld): HARDWAREVER=%s.\n", __func__, ha->host_no, + eiter->a.hw_version)); + + /* Driver version. */ + eiter = (struct ct_fdmi_hba_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_HBA_DRIVER_VERSION); + strcpy(eiter->a.driver_version, qla2x00_version_str); + alen = strlen(eiter->a.driver_version); + alen += (alen & 3) ? (4 - (alen & 3)) : 4; + eiter->len = cpu_to_be16(4 + alen); + size += 4 + alen; + + DEBUG13(printk("%s(%ld): DRIVERVER=%s.\n", __func__, ha->host_no, + eiter->a.driver_version)); + + /* Option ROM version. */ + eiter = (struct ct_fdmi_hba_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_HBA_OPTION_ROM_VERSION); + strcpy(eiter->a.orom_version, "0.00"); + alen = strlen(eiter->a.orom_version); + alen += (alen & 3) ? (4 - (alen & 3)) : 4; + eiter->len = cpu_to_be16(4 + alen); + size += 4 + alen; + + DEBUG13(printk("%s(%ld): OPTROMVER=%s.\n", __func__, ha->host_no, + eiter->a.orom_version)); + + /* Firmware version */ + eiter = (struct ct_fdmi_hba_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_HBA_FIRMWARE_VERSION); + ha->isp_ops.fw_version_str(ha, eiter->a.fw_version); + alen = strlen(eiter->a.fw_version); + alen += (alen & 3) ? (4 - (alen & 3)) : 4; + eiter->len = cpu_to_be16(4 + alen); + size += 4 + alen; + + DEBUG13(printk("%s(%ld): FIRMWAREVER=%s.\n", __func__, ha->host_no, + eiter->a.fw_version)); + + /* Update MS request size. */ + qla2x00_update_ms_fdmi_iocb(ha, size + 16); + + DEBUG13(printk("%s(%ld): RHBA identifier=" + "%02x%02x%02x%02x%02x%02x%02x%02x size=%d.\n", __func__, + ha->host_no, ct_req->req.rhba.hba_identifier[0], + ct_req->req.rhba.hba_identifier[1], + ct_req->req.rhba.hba_identifier[2], + ct_req->req.rhba.hba_identifier[3], + ct_req->req.rhba.hba_identifier[4], + ct_req->req.rhba.hba_identifier[5], + ct_req->req.rhba.hba_identifier[6], + ct_req->req.rhba.hba_identifier[7], size)); + DEBUG13(qla2x00_dump_buffer(entries, size)); + + /* Execute MS IOCB */ + rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma, + sizeof(ms_iocb_entry_t)); + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG2_3(printk("scsi(%ld): RHBA issue IOCB failed (%d).\n", + ha->host_no, rval)); + } else if (qla2x00_chk_ms_status(ha, ms_pkt, ct_rsp, "RHBA") != + QLA_SUCCESS) { + rval = QLA_FUNCTION_FAILED; + if (ct_rsp->header.reason_code == CT_REASON_CANNOT_PERFORM && + ct_rsp->header.explanation_code == + CT_EXPL_ALREADY_REGISTERED) { + DEBUG2_13(printk("%s(%ld): HBA already registered.\n", + __func__, ha->host_no)); + rval = QLA_ALREADY_REGISTERED; + } + } else { + DEBUG2(printk("scsi(%ld): RHBA exiting normally.\n", + ha->host_no)); + } + + return rval; +} + +/** + * qla2x00_fdmi_dhba() - + * @ha: HA context + * + * Returns 0 on success. + */ +static int +qla2x00_fdmi_dhba(scsi_qla_host_t *ha) +{ + int rval; + + ms_iocb_entry_t *ms_pkt; + struct ct_sns_req *ct_req; + struct ct_sns_rsp *ct_rsp; + + /* Issue RPA */ + /* Prepare common MS IOCB */ + ms_pkt = ha->isp_ops.prep_ms_fdmi_iocb(ha, DHBA_REQ_SIZE, + DHBA_RSP_SIZE); + + /* Prepare CT request */ + ct_req = qla2x00_prep_ct_fdmi_req(&ha->ct_sns->p.req, DHBA_CMD, + DHBA_RSP_SIZE); + ct_rsp = &ha->ct_sns->p.rsp; + + /* Prepare FDMI command arguments -- portname. */ + memcpy(ct_req->req.dhba.port_name, ha->port_name, WWN_SIZE); + + DEBUG13(printk("%s(%ld): DHBA portname=" + "%02x%02x%02x%02x%02x%02x%02x%02x.\n", __func__, ha->host_no, + ct_req->req.dhba.port_name[0], ct_req->req.dhba.port_name[1], + ct_req->req.dhba.port_name[2], ct_req->req.dhba.port_name[3], + ct_req->req.dhba.port_name[4], ct_req->req.dhba.port_name[5], + ct_req->req.dhba.port_name[6], ct_req->req.dhba.port_name[7])); + + /* Execute MS IOCB */ + rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma, + sizeof(ms_iocb_entry_t)); + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG2_3(printk("scsi(%ld): DHBA issue IOCB failed (%d).\n", + ha->host_no, rval)); + } else if (qla2x00_chk_ms_status(ha, ms_pkt, ct_rsp, "DHBA") != + QLA_SUCCESS) { + rval = QLA_FUNCTION_FAILED; + } else { + DEBUG2(printk("scsi(%ld): DHBA exiting normally.\n", + ha->host_no)); + } + + return rval; +} + +/** + * qla2x00_fdmi_rpa() - + * @ha: HA context + * + * Returns 0 on success. + */ +static int +qla2x00_fdmi_rpa(scsi_qla_host_t *ha) +{ + int rval, alen; + uint32_t size, max_frame_size; + + ms_iocb_entry_t *ms_pkt; + struct ct_sns_req *ct_req; + struct ct_sns_rsp *ct_rsp; + uint8_t *entries; + struct ct_fdmi_port_attr *eiter; + struct init_cb_24xx *icb24 = (struct init_cb_24xx *)ha->init_cb; + + /* Issue RPA */ + /* Prepare common MS IOCB */ + /* Request size adjusted after CT preparation */ + ms_pkt = ha->isp_ops.prep_ms_fdmi_iocb(ha, 0, RPA_RSP_SIZE); + + /* Prepare CT request */ + ct_req = qla2x00_prep_ct_fdmi_req(&ha->ct_sns->p.req, RPA_CMD, + RPA_RSP_SIZE); + ct_rsp = &ha->ct_sns->p.rsp; + + /* Prepare FDMI command arguments -- attribute block, attributes. */ + memcpy(ct_req->req.rpa.port_name, ha->port_name, WWN_SIZE); + size = WWN_SIZE + 4; + + /* Attributes */ + ct_req->req.rpa.attrs.count = + __constant_cpu_to_be32(FDMI_PORT_ATTR_COUNT); + entries = ct_req->req.rpa.port_name; + + /* FC4 types. */ + eiter = (struct ct_fdmi_port_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_PORT_FC4_TYPES); + eiter->len = __constant_cpu_to_be16(4 + 32); + eiter->a.fc4_types[2] = 0x01; + size += 4 + 32; + + DEBUG13(printk("%s(%ld): FC4_TYPES=%02x %02x.\n", __func__, ha->host_no, + eiter->a.fc4_types[2], eiter->a.fc4_types[1])); + + /* Supported speed. */ + eiter = (struct ct_fdmi_port_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_PORT_SUPPORT_SPEED); + eiter->len = __constant_cpu_to_be16(4 + 4); + if (IS_QLA25XX(ha)) + eiter->a.sup_speed = __constant_cpu_to_be32(4); + else if (IS_QLA24XX(ha)) + eiter->a.sup_speed = __constant_cpu_to_be32(8); + else if (IS_QLA23XX(ha)) + eiter->a.sup_speed = __constant_cpu_to_be32(2); + else + eiter->a.sup_speed = __constant_cpu_to_be32(1); + size += 4 + 4; + + DEBUG13(printk("%s(%ld): SUPPORTED_SPEED=%x.\n", __func__, ha->host_no, + eiter->a.sup_speed)); + + /* Current speed. */ + eiter = (struct ct_fdmi_port_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_PORT_CURRENT_SPEED); + eiter->len = __constant_cpu_to_be16(4 + 4); + switch (ha->link_data_rate) { + case 0: + eiter->a.cur_speed = __constant_cpu_to_be32(1); + break; + case 1: + eiter->a.cur_speed = __constant_cpu_to_be32(2); + break; + case 3: + eiter->a.cur_speed = __constant_cpu_to_be32(8); + break; + case 4: + eiter->a.cur_speed = __constant_cpu_to_be32(4); + break; + } + size += 4 + 4; + + DEBUG13(printk("%s(%ld): CURRENT_SPEED=%x.\n", __func__, ha->host_no, + eiter->a.cur_speed)); + + /* Max frame size. */ + eiter = (struct ct_fdmi_port_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_PORT_MAX_FRAME_SIZE); + eiter->len = __constant_cpu_to_be16(4 + 4); + max_frame_size = IS_QLA24XX(ha) || IS_QLA25XX(ha) ? + (uint32_t) icb24->frame_payload_size: + (uint32_t) ha->init_cb->frame_payload_size; + eiter->a.max_frame_size = cpu_to_be32(max_frame_size); + size += 4 + 4; + + DEBUG13(printk("%s(%ld): MAX_FRAME_SIZE=%x.\n", __func__, ha->host_no, + eiter->a.max_frame_size)); + + /* OS device name. */ + eiter = (struct ct_fdmi_port_attr *) (entries + size); + eiter->type = __constant_cpu_to_be16(FDMI_PORT_OS_DEVICE_NAME); + sprintf(eiter->a.os_dev_name, "/proc/scsi/qla2xxx/%ld", ha->host_no); + alen = strlen(eiter->a.os_dev_name); + alen += (alen & 3) ? (4 - (alen & 3)) : 4; + eiter->len = cpu_to_be16(4 + alen); + size += 4 + alen; + + DEBUG13(printk("%s(%ld): OS_DEVICE_NAME=%s.\n", __func__, ha->host_no, + eiter->a.os_dev_name)); + + /* Update MS request size. */ + qla2x00_update_ms_fdmi_iocb(ha, size + 16); + + DEBUG13(printk("%s(%ld): RPA portname=" + "%02x%02x%02x%02x%02x%02x%02x%02x size=%d.\n", __func__, + ha->host_no, ct_req->req.rpa.port_name[0], + ct_req->req.rpa.port_name[1], ct_req->req.rpa.port_name[2], + ct_req->req.rpa.port_name[3], ct_req->req.rpa.port_name[4], + ct_req->req.rpa.port_name[5], ct_req->req.rpa.port_name[6], + ct_req->req.rpa.port_name[7], size)); + DEBUG13(qla2x00_dump_buffer(entries, size)); + + /* Execute MS IOCB */ + rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma, + sizeof(ms_iocb_entry_t)); + if (rval != QLA_SUCCESS) { + /*EMPTY*/ + DEBUG2_3(printk("scsi(%ld): RPA issue IOCB failed (%d).\n", + ha->host_no, rval)); + } else if (qla2x00_chk_ms_status(ha, ms_pkt, ct_rsp, "RPA") != + QLA_SUCCESS) { + rval = QLA_FUNCTION_FAILED; + } else { + DEBUG2(printk("scsi(%ld): RPA exiting normally.\n", + ha->host_no)); + } + + return rval; +} + +/** + * qla2x00_fdmi_register() - + * @ha: HA context + * + * Returns 0 on success. + */ +int +qla2x00_fdmi_register(scsi_qla_host_t *ha) +{ + int rval; + + rval = qla2x00_mgmt_svr_login(ha); + if (rval) + return rval; + + rval = qla2x00_fdmi_rhba(ha); + if (rval) { + if (rval != QLA_ALREADY_REGISTERED) + return rval; + + rval = qla2x00_fdmi_dhba(ha); + if (rval) + return rval; + + rval = qla2x00_fdmi_rhba(ha); + if (rval) + return rval; + } + rval = qla2x00_fdmi_rpa(ha); + + return rval; +} diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 09b23f70fd66..e38d0cf73637 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -88,6 +88,7 @@ qla2x00_initialize_adapter(scsi_qla_host_t *ha) ha->mbx_flags = 0; ha->isp_abort_cnt = 0; ha->beacon_blink_led = 0; + set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags); qla_printk(KERN_INFO, ha, "Configuring PCI space...\n"); rval = ha->isp_ops.pci_config(ha); @@ -2132,6 +2133,11 @@ qla2x00_configure_fabric(scsi_qla_host_t *ha) return (QLA_SUCCESS); } do { + /* FDMI support. */ + if (ql2xfdmienable && + test_and_clear_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags)) + qla2x00_fdmi_register(ha); + /* Ensure we are logged into the SNS. */ if (IS_QLA24XX(ha) || IS_QLA25XX(ha)) loop_id = NPH_SNS; diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index f910de6dd437..c255bb0268a9 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -451,6 +451,8 @@ qla2x00_async_event(scsi_qla_host_t *ha, uint16_t *mb) ha->flags.management_server_logged_in = 0; ha->link_data_rate = 0; + if (ql2xfdmienable) + set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags); /* Update AEN queue. */ qla2x00_enqueue_aen(ha, MBA_LOOP_DOWN, NULL); diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 774309a77c05..284eb847e50f 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -252,7 +252,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp) mb0 = RD_REG_WORD(®->isp24.mailbox0); ictrl = RD_REG_DWORD(®->isp24.ictrl); } else { - mb0 = RD_MAILBOX_REG(ha, reg->isp, 0); + mb0 = RD_MAILBOX_REG(ha, ®->isp, 0); ictrl = RD_REG_WORD(®->isp.ictrl); } printk("%s(%ld): **** MB Command Timeout for cmd %x ****\n", diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 995e521b07de..0fc37d810e05 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -88,6 +88,12 @@ static void qla2x00_free_device(scsi_qla_host_t *); static void qla2x00_config_dma_addressing(scsi_qla_host_t *ha); +int ql2xfdmienable; +module_param(ql2xfdmienable, int, S_IRUGO|S_IRUSR); +MODULE_PARM_DESC(ql2xfdmienable, + "Enables FDMI registratons " + "Default is 0 - no FDMI. 1 - perfom FDMI."); + /* * SCSI host template entry points */ @@ -1303,6 +1309,7 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info) ha->prev_topology = 0; ha->ports = MAX_BUSES; ha->init_cb_size = sizeof(init_cb_t); + ha->mgmt_svr_loop_id = MANAGEMENT_SERVER; /* Assign ISP specific operations. */ ha->isp_ops.pci_config = qla2100_pci_config; @@ -1325,6 +1332,7 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info) ha->isp_ops.calc_req_entries = qla2x00_calc_iocbs_32; ha->isp_ops.build_iocbs = qla2x00_build_scsi_iocbs_32; ha->isp_ops.prep_ms_iocb = qla2x00_prep_ms_iocb; + ha->isp_ops.prep_ms_fdmi_iocb = qla2x00_prep_ms_fdmi_iocb; ha->isp_ops.read_nvram = qla2x00_read_nvram_data; ha->isp_ops.write_nvram = qla2x00_write_nvram_data; ha->isp_ops.fw_dump = qla2100_fw_dump; @@ -1362,6 +1370,7 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info) ha->response_q_length = RESPONSE_ENTRY_CNT_2300; ha->last_loop_id = SNS_LAST_LOOP_ID_2300; ha->init_cb_size = sizeof(struct init_cb_24xx); + ha->mgmt_svr_loop_id = 10; ha->isp_ops.pci_config = qla24xx_pci_config; ha->isp_ops.reset_chip = qla24xx_reset_chip; ha->isp_ops.chip_diag = qla24xx_chip_diag; @@ -1382,6 +1391,7 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info) ha->isp_ops.fabric_login = qla24xx_login_fabric; ha->isp_ops.fabric_logout = qla24xx_fabric_logout; ha->isp_ops.prep_ms_iocb = qla24xx_prep_ms_iocb; + ha->isp_ops.prep_ms_fdmi_iocb = qla24xx_prep_ms_fdmi_iocb; ha->isp_ops.read_nvram = qla24xx_read_nvram_data; ha->isp_ops.write_nvram = qla24xx_write_nvram_data; ha->isp_ops.fw_dump = qla24xx_fw_dump; From f7d289f62e2ea911ecb710015efd45c687fa81ce Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 26 Aug 2005 19:08:40 -0700 Subject: [PATCH 096/114] [SCSI] qla2xxx: Correct domain/area exclusion logic. In an FL topology, limit port recognition to those devices not within the same area and domain of the ISP. The firmware will recogonize such devices during local-loop discovery. Some devices may respond to a PLOGI before they have completed their fabric login or they may not be a public device. In this case they will report: domain == 00 area == 00 alpa == which is valid. Exclude such devices from local loop discovery. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_init.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index e38d0cf73637..d12255fb9383 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1900,7 +1900,8 @@ qla2x00_configure_local_loop(scsi_qla_host_t *ha) continue; /* Bypass if not same domain and area of adapter. */ - if (area != ha->d_id.b.area || domain != ha->d_id.b.domain) + if (area && domain && + (area != ha->d_id.b.area || domain != ha->d_id.b.domain)) continue; /* Bypass invalid local loop ID. */ @@ -2400,6 +2401,12 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports) if (new_fcport->d_id.b24 == ha->d_id.b24) continue; + /* Bypass if same domain and area of adapter. */ + if (((new_fcport->d_id.b24 & 0xffff00) == + (ha->d_id.b24 & 0xffff00)) && ha->current_topology == + ISP_CFG_FL) + continue; + /* Bypass reserved domain fields. */ if ((new_fcport->d_id.b.domain & 0xf0) == 0xf0) continue; From c00c72ae01c03d3d172150392419040f8d55ab04 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 26 Aug 2005 19:08:50 -0700 Subject: [PATCH 097/114] [SCSI] qla2xxx: Simplify redundant target/device reset logic. Remove redundant qla2x00_target_reset() function in favour of the equivalent qla2x00_device_reset(). Update callers of old function. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_gbl.h | 3 -- drivers/scsi/qla2xxx/qla_mbx.c | 52 ---------------------------------- drivers/scsi/qla2xxx/qla_os.c | 2 +- 3 files changed, 1 insertion(+), 56 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 3e1e5fe850a0..5deaa7e6ee60 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -147,9 +147,6 @@ extern int qla2x00_abort_target(fc_port_t *); #endif -extern int -qla2x00_target_reset(scsi_qla_host_t *, struct fc_port *); - extern int qla2x00_get_adapter_id(scsi_qla_host_t *, uint16_t *, uint8_t *, uint8_t *, uint8_t *, uint16_t *); diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 284eb847e50f..953156faafdb 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -983,58 +983,6 @@ qla2x00_abort_target(fc_port_t *fcport) } #endif -/* - * qla2x00_target_reset - * Issue target reset mailbox command. - * - * Input: - * ha = adapter block pointer. - * TARGET_QUEUE_LOCK must be released. - * ADAPTER_STATE_LOCK must be released. - * - * Returns: - * qla2x00 local function return status code. - * - * Context: - * Kernel context. - */ -int -qla2x00_target_reset(scsi_qla_host_t *ha, struct fc_port *fcport) -{ - int rval; - mbx_cmd_t mc; - mbx_cmd_t *mcp = &mc; - - DEBUG11(printk("qla2x00_target_reset(%ld): entered.\n", ha->host_no);) - - if (atomic_read(&fcport->state) != FCS_ONLINE) - return 0; - - mcp->mb[0] = MBC_TARGET_RESET; - if (HAS_EXTENDED_IDS(ha)) - mcp->mb[1] = fcport->loop_id; - else - mcp->mb[1] = fcport->loop_id << 8; - mcp->mb[2] = ha->loop_reset_delay; - mcp->out_mb = MBX_2|MBX_1|MBX_0; - mcp->in_mb = MBX_0; - mcp->tov = 30; - mcp->flags = 0; - rval = qla2x00_mailbox_command(ha, mcp); - - if (rval != QLA_SUCCESS) { - /*EMPTY*/ - DEBUG2_3_11(printk("qla2x00_target_reset(%ld): failed=%x.\n", - ha->host_no, rval);) - } else { - /*EMPTY*/ - DEBUG11(printk("qla2x00_target_reset(%ld): done.\n", - ha->host_no);) - } - - return rval; -} - /* * qla2x00_get_adapter_id * Get adapter ID and topology. diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 0fc37d810e05..29cf3f510935 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1022,7 +1022,7 @@ qla2x00_loop_reset(scsi_qla_host_t *ha) if (fcport->port_type != FCT_TARGET) continue; - status = qla2x00_target_reset(ha, fcport); + status = qla2x00_device_reset(ha, fcport); if (status != QLA_SUCCESS) break; } From 06c22bd13f4eb55e291d5a31280b2ae5a70ad00d Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 26 Aug 2005 19:09:00 -0700 Subject: [PATCH 098/114] [SCSI] qla2xxx: Correct LED scheme definition. Original implementation used an overloaded bit in the EFI parameters. The correct bit is BIT_4 of the special_options section of NVRAM. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_def.h | 4 ++-- drivers/scsi/qla2xxx/qla_init.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index cdef86e49c60..b7f82b757cbc 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -914,7 +914,7 @@ typedef struct { * MSB BIT 1 = * MSB BIT 2 = * MSB BIT 3 = - * MSB BIT 4 = + * MSB BIT 4 = LED mode * MSB BIT 5 = enable 50 ohm termination * MSB BIT 6 = Data Rate (2300 only) * MSB BIT 7 = Data Rate (2300 only) @@ -1036,7 +1036,7 @@ typedef struct { * MSB BIT 1 = * MSB BIT 2 = * MSB BIT 3 = - * MSB BIT 4 = + * MSB BIT 4 = LED mode * MSB BIT 5 = enable 50 ohm termination * MSB BIT 6 = Data Rate (2300 only) * MSB BIT 7 = Data Rate (2300 only) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index d12255fb9383..c619583e646b 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1564,7 +1564,7 @@ qla2x00_nvram_config(scsi_qla_host_t *ha) ha->flags.enable_lip_reset = ((nv->host_p[1] & BIT_1) ? 1 : 0); ha->flags.enable_lip_full_login = ((nv->host_p[1] & BIT_2) ? 1 : 0); ha->flags.enable_target_reset = ((nv->host_p[1] & BIT_3) ? 1 : 0); - ha->flags.enable_led_scheme = ((nv->efi_parameters & BIT_3) ? 1 : 0); + ha->flags.enable_led_scheme = (nv->special_options[1] & BIT_4) ? 1 : 0; ha->operating_mode = (icb->add_firmware_options[0] & (BIT_6 | BIT_5 | BIT_4)) >> 4; From c32c4cb9fbe3bdc2a90c6eaae5ae30521d4ba9fc Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 26 Aug 2005 19:09:10 -0700 Subject: [PATCH 099/114] [SCSI] qla2xxx: Remove RISC pause/release barriers during flash manipulation. Remove unnecessary RISC pause/release barriers during ISP24xx flash manipulation. The ISP24xx can arbitrate flash access requests during RISC executions. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_sup.c | 34 ---------------------------------- 1 file changed, 34 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c index d7f5c608009c..c14abf743b7c 100644 --- a/drivers/scsi/qla2xxx/qla_sup.c +++ b/drivers/scsi/qla2xxx/qla_sup.c @@ -468,21 +468,12 @@ qla24xx_read_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, uint32_t dwords) { uint32_t i; - struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; - - /* Pause RISC. */ - WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_PAUSE); - RD_REG_DWORD(®->hccr); /* PCI Posting. */ /* Dword reads to flash. */ for (i = 0; i < dwords; i++, faddr++) dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(ha, flash_data_to_access_addr(faddr))); - /* Release RISC pause. */ - WRT_REG_DWORD(®->hccr, HCCRX_REL_RISC_PAUSE); - RD_REG_DWORD(®->hccr); /* PCI Posting. */ - return dwptr; } @@ -532,10 +523,6 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, ret = QLA_SUCCESS; - /* Pause RISC. */ - WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_PAUSE); - RD_REG_DWORD(®->hccr); /* PCI Posting. */ - qla24xx_get_flash_manufacturer(ha, &man_id, &flash_id); DEBUG9(printk("%s(%ld): Flash man_id=%d flash_id=%d\n", __func__, ha->host_no, man_id, flash_id)); @@ -599,10 +586,6 @@ qla24xx_write_flash_data(scsi_qla_host_t *ha, uint32_t *dwptr, uint32_t faddr, RD_REG_DWORD(®->ctrl_status) & ~CSRX_FLASH_ENABLE); RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */ - /* Release RISC pause. */ - WRT_REG_DWORD(®->hccr, HCCRX_REL_RISC_PAUSE); - RD_REG_DWORD(®->hccr); /* PCI Posting. */ - return ret; } @@ -630,11 +613,6 @@ qla24xx_read_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr, { uint32_t i; uint32_t *dwptr; - struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; - - /* Pause RISC. */ - WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_PAUSE); - RD_REG_DWORD(®->hccr); /* PCI Posting. */ /* Dword reads to flash. */ dwptr = (uint32_t *)buf; @@ -642,10 +620,6 @@ qla24xx_read_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr, dwptr[i] = cpu_to_le32(qla24xx_read_flash_dword(ha, nvram_data_to_access_addr(naddr))); - /* Release RISC pause. */ - WRT_REG_DWORD(®->hccr, HCCRX_REL_RISC_PAUSE); - RD_REG_DWORD(®->hccr); /* PCI Posting. */ - return buf; } @@ -690,10 +664,6 @@ qla24xx_write_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr, ret = QLA_SUCCESS; - /* Pause RISC. */ - WRT_REG_DWORD(®->hccr, HCCRX_SET_RISC_PAUSE); - RD_REG_DWORD(®->hccr); /* PCI Posting. */ - /* Enable flash write. */ WRT_REG_DWORD(®->ctrl_status, RD_REG_DWORD(®->ctrl_status) | CSRX_FLASH_ENABLE); @@ -728,9 +698,5 @@ qla24xx_write_nvram_data(scsi_qla_host_t *ha, uint8_t *buf, uint32_t naddr, RD_REG_DWORD(®->ctrl_status) & ~CSRX_FLASH_ENABLE); RD_REG_DWORD(®->ctrl_status); /* PCI Posting. */ - /* Release RISC pause. */ - WRT_REG_DWORD(®->hccr, HCCRX_REL_RISC_PAUSE); - RD_REG_DWORD(®->hccr); /* PCI Posting. */ - return ret; } From 131736d34ebc3251d79ddfd08a5e57a3e86decd4 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 26 Aug 2005 19:09:20 -0700 Subject: [PATCH 100/114] [SCSI] qla2xxx: Remove redundant call to pci_unmap_sg(). In a corner-case failure where the request-q does not contain enough entries for a given request, pci_unmap_sg() would be called twice. Remove direct call and let the failure-path logic handle the unmapping. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_iocb.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index ebdc3c54d155..37f82e2cd7fb 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -810,12 +810,8 @@ qla24xx_start_scsi(srb_t *sp) ha->req_q_cnt = ha->request_q_length - (ha->req_ring_index - cnt); } - if (ha->req_q_cnt < (req_cnt + 2)) { - if (cmd->use_sg) - pci_unmap_sg(ha->pdev, sg, cmd->use_sg, - cmd->sc_data_direction); + if (ha->req_q_cnt < (req_cnt + 2)) goto queuing_error; - } /* Build command packet. */ ha->current_outstanding_cmd = handle; From ce7e4af7f507c156c3fd3dbb41ffe4a77c700b54 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 26 Aug 2005 19:09:30 -0700 Subject: [PATCH 101/114] [SCSI] qla2xxx: Add change_queue_depth/type() API support. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_os.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 29cf3f510935..413ccc152de5 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -111,6 +111,9 @@ static int qla2xxx_eh_host_reset(struct scsi_cmnd *); static int qla2x00_loop_reset(scsi_qla_host_t *ha); static int qla2x00_device_reset(scsi_qla_host_t *, fc_port_t *); +static int qla2x00_change_queue_depth(struct scsi_device *, int); +static int qla2x00_change_queue_type(struct scsi_device *, int); + static struct scsi_host_template qla2x00_driver_template = { .module = THIS_MODULE, .name = "qla2xxx", @@ -125,6 +128,8 @@ static struct scsi_host_template qla2x00_driver_template = { .slave_alloc = qla2xxx_slave_alloc, .slave_destroy = qla2xxx_slave_destroy, + .change_queue_depth = qla2x00_change_queue_depth, + .change_queue_type = qla2x00_change_queue_type, .this_id = -1, .cmd_per_lun = 3, .use_clustering = ENABLE_CLUSTERING, @@ -151,6 +156,8 @@ static struct scsi_host_template qla24xx_driver_template = { .slave_alloc = qla2xxx_slave_alloc, .slave_destroy = qla2xxx_slave_destroy, + .change_queue_depth = qla2x00_change_queue_depth, + .change_queue_type = qla2x00_change_queue_type, .this_id = -1, .cmd_per_lun = 3, .use_clustering = ENABLE_CLUSTERING, @@ -1109,6 +1116,28 @@ qla2xxx_slave_destroy(struct scsi_device *sdev) sdev->hostdata = NULL; } +static int +qla2x00_change_queue_depth(struct scsi_device *sdev, int qdepth) +{ + scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth); + return sdev->queue_depth; +} + +static int +qla2x00_change_queue_type(struct scsi_device *sdev, int tag_type) +{ + if (sdev->tagged_supported) { + scsi_set_tag_type(sdev, tag_type); + if (tag_type) + scsi_activate_tcq(sdev, sdev->queue_depth); + else + scsi_deactivate_tcq(sdev, sdev->queue_depth); + } else + tag_type = 0; + + return tag_type; +} + /** * qla2x00_config_dma_addressing() - Configure OS DMA addressing method. * @ha: HA context From afb046e2be724a90f21f7cf0ba50e328005bd038 Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 26 Aug 2005 19:09:40 -0700 Subject: [PATCH 102/114] [SCSI] qla2xxx: Add host attributes. Export additional host information via the shost_attrs member in the scsi_host template. Attributes include: driver version, firmware version, ISP serial number, ISP type, ISP product ID, HBA model name, HBA model description, PCI interconnect information, and HBA port state. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_attr.c | 132 ++++++++++++++++++++++++++++++++ drivers/scsi/qla2xxx/qla_gbl.h | 2 + drivers/scsi/qla2xxx/qla_os.c | 2 + 3 files changed, 136 insertions(+) diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index d05280eecc60..fe0fce71adc7 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -211,6 +211,138 @@ qla2x00_free_sysfs_attr(scsi_qla_host_t *ha) sysfs_remove_bin_file(&host->shost_gendev.kobj, &sysfs_nvram_attr); } +/* Scsi_Host attributes. */ + +static ssize_t +qla2x00_drvr_version_show(struct class_device *cdev, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%s\n", qla2x00_version_str); +} + +static ssize_t +qla2x00_fw_version_show(struct class_device *cdev, char *buf) +{ + scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + char fw_str[30]; + + return snprintf(buf, PAGE_SIZE, "%s\n", + ha->isp_ops.fw_version_str(ha, fw_str)); +} + +static ssize_t +qla2x00_serial_num_show(struct class_device *cdev, char *buf) +{ + scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + uint32_t sn; + + sn = ((ha->serial0 & 0x1f) << 16) | (ha->serial2 << 8) | ha->serial1; + return snprintf(buf, PAGE_SIZE, "%c%05d\n", 'A' + sn / 100000, + sn % 100000); +} + +static ssize_t +qla2x00_isp_name_show(struct class_device *cdev, char *buf) +{ + scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + return snprintf(buf, PAGE_SIZE, "%s\n", ha->brd_info->isp_name); +} + +static ssize_t +qla2x00_isp_id_show(struct class_device *cdev, char *buf) +{ + scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + return snprintf(buf, PAGE_SIZE, "%04x %04x %04x %04x\n", + ha->product_id[0], ha->product_id[1], ha->product_id[2], + ha->product_id[3]); +} + +static ssize_t +qla2x00_model_name_show(struct class_device *cdev, char *buf) +{ + scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + return snprintf(buf, PAGE_SIZE, "%s\n", ha->model_number); +} + +static ssize_t +qla2x00_model_desc_show(struct class_device *cdev, char *buf) +{ + scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + return snprintf(buf, PAGE_SIZE, "%s\n", + ha->model_desc ? ha->model_desc: ""); +} + +static ssize_t +qla2x00_pci_info_show(struct class_device *cdev, char *buf) +{ + scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + char pci_info[30]; + + return snprintf(buf, PAGE_SIZE, "%s\n", + ha->isp_ops.pci_info_str(ha, pci_info)); +} + +static ssize_t +qla2x00_state_show(struct class_device *cdev, char *buf) +{ + scsi_qla_host_t *ha = to_qla_host(class_to_shost(cdev)); + int len = 0; + + if (atomic_read(&ha->loop_state) == LOOP_DOWN || + atomic_read(&ha->loop_state) == LOOP_DEAD) + len = snprintf(buf, PAGE_SIZE, "Link Down\n"); + else if (atomic_read(&ha->loop_state) != LOOP_READY || + test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) || + test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) + len = snprintf(buf, PAGE_SIZE, "Unknown Link State\n"); + else { + len = snprintf(buf, PAGE_SIZE, "Link Up - "); + + switch (ha->current_topology) { + case ISP_CFG_NL: + len += snprintf(buf + len, PAGE_SIZE-len, "Loop\n"); + break; + case ISP_CFG_FL: + len += snprintf(buf + len, PAGE_SIZE-len, "FL_Port\n"); + break; + case ISP_CFG_N: + len += snprintf(buf + len, PAGE_SIZE-len, + "N_Port to N_Port\n"); + break; + case ISP_CFG_F: + len += snprintf(buf + len, PAGE_SIZE-len, "F_Port\n"); + break; + default: + len += snprintf(buf + len, PAGE_SIZE-len, "Loop\n"); + break; + } + } + return len; +} + +static CLASS_DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show, + NULL); +static CLASS_DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL); +static CLASS_DEVICE_ATTR(serial_num, S_IRUGO, qla2x00_serial_num_show, NULL); +static CLASS_DEVICE_ATTR(isp_name, S_IRUGO, qla2x00_isp_name_show, NULL); +static CLASS_DEVICE_ATTR(isp_id, S_IRUGO, qla2x00_isp_id_show, NULL); +static CLASS_DEVICE_ATTR(model_name, S_IRUGO, qla2x00_model_name_show, NULL); +static CLASS_DEVICE_ATTR(model_desc, S_IRUGO, qla2x00_model_desc_show, NULL); +static CLASS_DEVICE_ATTR(pci_info, S_IRUGO, qla2x00_pci_info_show, NULL); +static CLASS_DEVICE_ATTR(state, S_IRUGO, qla2x00_state_show, NULL); + +struct class_device_attribute *qla2x00_host_attrs[] = { + &class_device_attr_driver_version, + &class_device_attr_fw_version, + &class_device_attr_serial_num, + &class_device_attr_isp_name, + &class_device_attr_isp_id, + &class_device_attr_model_name, + &class_device_attr_model_desc, + &class_device_attr_pci_info, + &class_device_attr_state, + NULL, +}; + /* Host attributes. */ static void diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 5deaa7e6ee60..95fb0c4941aa 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -290,6 +290,8 @@ extern void qla2x00_cancel_io_descriptors(scsi_qla_host_t *); /* * Global Function Prototypes in qla_attr.c source file. */ +struct class_device_attribute; +extern struct class_device_attribute *qla2x00_host_attrs[]; struct fc_function_template; extern struct fc_function_template qla2xxx_transport_functions; extern void qla2x00_alloc_sysfs_attr(scsi_qla_host_t *); diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 413ccc152de5..14f2f9077c81 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -140,6 +140,7 @@ static struct scsi_host_template qla2x00_driver_template = { * which equates to 0x800000 sectors. */ .max_sectors = 0xFFFF, + .shost_attrs = qla2x00_host_attrs, }; static struct scsi_host_template qla24xx_driver_template = { @@ -164,6 +165,7 @@ static struct scsi_host_template qla24xx_driver_template = { .sg_tablesize = SG_ALL, .max_sectors = 0xFFFF, + .shost_attrs = qla2x00_host_attrs, }; static struct scsi_transport_template *qla2xxx_transport_template = NULL; From 86cd6baa8294dc5b2cedd84fb5cf3944eaf5271f Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 26 Aug 2005 19:10:00 -0700 Subject: [PATCH 103/114] [SCSI] qla2xxx: Remove bad call to fc_remove_host() during probe failure. fc_remove_host() should only be called after a scsi_host has been successfully added via scsi_add_host() -- any failures while qla2xxx probing would result in an incorrect call to fc_remove_host() during cleanup. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_os.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 14f2f9077c81..5a542655d442 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -1586,8 +1586,6 @@ int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info) return 0; probe_failed: - fc_remove_host(ha->host); - qla2x00_free_device(ha); scsi_host_put(host); From fe74c71f6bb63376d92bc606597f0818f5b11c2e Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 26 Aug 2005 19:10:10 -0700 Subject: [PATCH 104/114] [SCSI] qla2xxx: Replace schedule_timeout(). From: Nishanth Aravamudan Replace schedule_timeout() with msleep()/msleep_interruptible() as appropriate, to guarantee the task delays as expected. Signed-off-by: Nishanth Aravamudan Signed-off-by: Domen Puncer Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_os.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 5a542655d442..af9b4e77cbff 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -502,14 +502,13 @@ qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) static int qla2x00_eh_wait_on_command(scsi_qla_host_t *ha, struct scsi_cmnd *cmd) { -#define ABORT_POLLING_PERIOD HZ -#define ABORT_WAIT_ITER ((10 * HZ) / (ABORT_POLLING_PERIOD)) +#define ABORT_POLLING_PERIOD 1000 +#define ABORT_WAIT_ITER ((10 * 1000) / (ABORT_POLLING_PERIOD)) unsigned long wait_iter = ABORT_WAIT_ITER; int ret = QLA_SUCCESS; while (CMD_SP(cmd)) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(ABORT_POLLING_PERIOD); + msleep(ABORT_POLLING_PERIOD); if (--wait_iter) break; @@ -1960,7 +1959,7 @@ qla2x00_mem_free(scsi_qla_host_t *ha) { struct list_head *fcpl, *fcptemp; fc_port_t *fcport; - unsigned long wtime;/* max wait time if mbx cmd is busy. */ + unsigned int wtime;/* max wait time if mbx cmd is busy. */ if (ha == NULL) { /* error */ @@ -1969,11 +1968,9 @@ qla2x00_mem_free(scsi_qla_host_t *ha) } /* Make sure all other threads are stopped. */ - wtime = 60 * HZ; - while (ha->dpc_wait && wtime) { - set_current_state(TASK_INTERRUPTIBLE); - wtime = schedule_timeout(wtime); - } + wtime = 60 * 1000; + while (ha->dpc_wait && wtime) + wtime = msleep_interruptible(wtime); /* free ioctl memory */ qla2x00_free_ioctl_mem(ha); @@ -2504,15 +2501,15 @@ qla2x00_timer(scsi_qla_host_t *ha) int qla2x00_down_timeout(struct semaphore *sema, unsigned long timeout) { - const unsigned int step = HZ/10; + const unsigned int step = 100; /* msecs */ + unsigned int iterations = jiffies_to_msecs(timeout)/100; do { if (!down_trylock(sema)) return 0; - set_current_state(TASK_INTERRUPTIBLE); - if (schedule_timeout(step)) + if (msleep_interruptible(step)) break; - } while ((timeout -= step) > 0); + } while (--iterations >= 0); return -ETIMEDOUT; } From f6ef3b1872915c6d69ca36cf4ca16269cb9a73ad Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 26 Aug 2005 19:10:20 -0700 Subject: [PATCH 105/114] [SCSI] qla2xxx: Stop firmware execution at unintialization time. On ISP24xx parts, stop execution of firmware during ISP tear-down. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_def.h | 1 + drivers/scsi/qla2xxx/qla_gbl.h | 3 +++ drivers/scsi/qla2xxx/qla_mbx.c | 29 +++++++++++++++++++++++++++++ drivers/scsi/qla2xxx/qla_os.c | 14 ++++++++------ 4 files changed, 41 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index b7f82b757cbc..b455c31405e4 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -631,6 +631,7 @@ typedef struct { #define MBC_WRITE_RAM_WORD_EXTENDED 0xd /* Write RAM word extended */ #define MBC_READ_RAM_EXTENDED 0xf /* Read RAM extended. */ #define MBC_IOCB_COMMAND 0x12 /* Execute IOCB command. */ +#define MBC_STOP_FIRMWARE 0x14 /* Stop firmware. */ #define MBC_ABORT_COMMAND 0x15 /* Abort IOCB command. */ #define MBC_ABORT_DEVICE 0x16 /* Abort device (ID/LUN). */ #define MBC_ABORT_TARGET 0x17 /* Abort target (ID). */ diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 95fb0c4941aa..1ed32e7b5472 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -213,6 +213,9 @@ qla2x00_get_serdes_params(scsi_qla_host_t *, uint16_t *, uint16_t *, extern int qla2x00_set_serdes_params(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t); +extern int +qla2x00_stop_firmware(scsi_qla_host_t *); + /* * Global Function Prototypes in qla_isr.c source file. */ diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 953156faafdb..13e1c9047079 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -2427,3 +2427,32 @@ qla2x00_set_serdes_params(scsi_qla_host_t *ha, uint16_t sw_em_1g, return rval; } + +int +qla2x00_stop_firmware(scsi_qla_host_t *ha) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + + if (!IS_QLA24XX(ha) && !IS_QLA25XX(ha)) + return QLA_FUNCTION_FAILED; + + DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no)); + + mcp->mb[0] = MBC_STOP_FIRMWARE; + mcp->out_mb = MBX_0; + mcp->in_mb = MBX_0; + mcp->tov = 5; + mcp->flags = 0; + rval = qla2x00_mailbox_command(ha, mcp); + + if (rval != QLA_SUCCESS) { + DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__, + ha->host_no, rval)); + } else { + DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no)); + } + + return rval; +} diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index af9b4e77cbff..8982978c42fd 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -79,7 +79,7 @@ module_param(ql2xloginretrycount, int, S_IRUGO|S_IRUSR); MODULE_PARM_DESC(ql2xloginretrycount, "Specify an alternate value for the NVRAM login retry count."); -int ql2xfwloadbin; +int ql2xfwloadbin=1; module_param(ql2xfwloadbin, int, S_IRUGO|S_IRUSR); MODULE_PARM_DESC(ql2xfwloadbin, "Load ISP2xxx firmware image via hotplug."); @@ -1626,10 +1626,6 @@ qla2x00_free_device(scsi_qla_host_t *ha) if (!IS_QLA2100(ha) && !IS_QLA2200(ha)) qla2x00_cancel_io_descriptors(ha); - /* turn-off interrupts on the card */ - if (ha->interrupts_on) - ha->isp_ops.disable_intrs(ha); - /* Disable timer */ if (ha->timer_active) qla2x00_stop_timer(ha); @@ -1649,8 +1645,14 @@ qla2x00_free_device(scsi_qla_host_t *ha) } } - qla2x00_mem_free(ha); + /* Stop currently executing firmware. */ + qla2x00_stop_firmware(ha); + /* turn-off interrupts on the card */ + if (ha->interrupts_on) + ha->isp_ops.disable_intrs(ha); + + qla2x00_mem_free(ha); ha->flags.online = 0; From 1aab60c25e9a500b9f15c1dfd775e70e7bde555c Mon Sep 17 00:00:00 2001 From: Andrew Vasquez Date: Fri, 26 Aug 2005 19:10:30 -0700 Subject: [PATCH 106/114] [SCSI] qla2xxx: Update version number to 8.01.00-k. Signed-off-by: Andrew Vasquez Signed-off-by: James Bottomley --- drivers/scsi/qla2xxx/qla_version.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index e3cd3618bc54..eae7d6edd531 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -19,9 +19,9 @@ /* * Driver version */ -#define QLA2XXX_VERSION "8.01.00b5-k" +#define QLA2XXX_VERSION "8.01.00-k" #define QLA_DRIVER_MAJOR_VER 8 #define QLA_DRIVER_MINOR_VER 1 #define QLA_DRIVER_PATCH_VER 0 -#define QLA_DRIVER_BETA_VER 5 +#define QLA_DRIVER_BETA_VER 0 From 4dddbc26c3895ecdab1f4b16435685b47f96f599 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Tue, 6 Sep 2005 17:11:54 -0500 Subject: [PATCH 107/114] [SCSI] ibmvscsi: handle large scatter/gather lists The maximum size of a scatter-gather list that the current IBM VSCSI Client can handle is 10. This patch adds large scatter-gather support to the client so that it is capable of handling up to SG_ALL(255) number of requests in the scatter-gather list. Signed-off-by: Linda Xie Acked by: Dave C Boutcher Rejections fixed up and Signed-off-by: James Bottomley --- drivers/scsi/ibmvscsi/ibmvscsi.c | 166 ++++++++++++++++++++++--------- drivers/scsi/ibmvscsi/ibmvscsi.h | 2 + 2 files changed, 121 insertions(+), 47 deletions(-) diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index e3e6752c4104..1b911dadf64b 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -87,7 +87,7 @@ static int max_channel = 3; static int init_timeout = 5; static int max_requests = 50; -#define IBMVSCSI_VERSION "1.5.6" +#define IBMVSCSI_VERSION "1.5.7" MODULE_DESCRIPTION("IBM Virtual SCSI"); MODULE_AUTHOR("Dave Boutcher"); @@ -145,6 +145,8 @@ static int initialize_event_pool(struct event_pool *pool, sizeof(*evt->xfer_iu) * i; evt->xfer_iu = pool->iu_storage + i; evt->hostdata = hostdata; + evt->ext_list = NULL; + evt->ext_list_token = 0; } return 0; @@ -161,9 +163,16 @@ static void release_event_pool(struct event_pool *pool, struct ibmvscsi_host_data *hostdata) { int i, in_use = 0; - for (i = 0; i < pool->size; ++i) + for (i = 0; i < pool->size; ++i) { if (atomic_read(&pool->events[i].free) != 1) ++in_use; + if (pool->events[i].ext_list) { + dma_free_coherent(hostdata->dev, + SG_ALL * sizeof(struct memory_descriptor), + pool->events[i].ext_list, + pool->events[i].ext_list_token); + } + } if (in_use) printk(KERN_WARNING "ibmvscsi: releasing event pool with %d " @@ -286,24 +295,41 @@ static void set_srp_direction(struct scsi_cmnd *cmd, } else { if (cmd->sc_data_direction == DMA_TO_DEVICE) { srp_cmd->data_out_format = SRP_INDIRECT_BUFFER; - srp_cmd->data_out_count = numbuf; + srp_cmd->data_out_count = + numbuf < MAX_INDIRECT_BUFS ? + numbuf: MAX_INDIRECT_BUFS; } else { srp_cmd->data_in_format = SRP_INDIRECT_BUFFER; - srp_cmd->data_in_count = numbuf; + srp_cmd->data_in_count = + numbuf < MAX_INDIRECT_BUFS ? + numbuf: MAX_INDIRECT_BUFS; } } } +static void unmap_sg_list(int num_entries, + struct device *dev, + struct memory_descriptor *md) +{ + int i; + + for (i = 0; i < num_entries; ++i) { + dma_unmap_single(dev, + md[i].virtual_address, + md[i].length, DMA_BIDIRECTIONAL); + } +} + /** * unmap_cmd_data: - Unmap data pointed in srp_cmd based on the format * @cmd: srp_cmd whose additional_data member will be unmapped * @dev: device for which the memory is mapped * */ -static void unmap_cmd_data(struct srp_cmd *cmd, struct device *dev) +static void unmap_cmd_data(struct srp_cmd *cmd, + struct srp_event_struct *evt_struct, + struct device *dev) { - int i; - if ((cmd->data_out_format == SRP_NO_BUFFER) && (cmd->data_in_format == SRP_NO_BUFFER)) return; @@ -318,15 +344,34 @@ static void unmap_cmd_data(struct srp_cmd *cmd, struct device *dev) (struct indirect_descriptor *)cmd->additional_data; int num_mapped = indirect->head.length / sizeof(indirect->list[0]); - for (i = 0; i < num_mapped; ++i) { - struct memory_descriptor *data = &indirect->list[i]; - dma_unmap_single(dev, - data->virtual_address, - data->length, DMA_BIDIRECTIONAL); + + if (num_mapped <= MAX_INDIRECT_BUFS) { + unmap_sg_list(num_mapped, dev, &indirect->list[0]); + return; } + + unmap_sg_list(num_mapped, dev, evt_struct->ext_list); } } +static int map_sg_list(int num_entries, + struct scatterlist *sg, + struct memory_descriptor *md) +{ + int i; + u64 total_length = 0; + + for (i = 0; i < num_entries; ++i) { + struct memory_descriptor *descr = md + i; + struct scatterlist *sg_entry = &sg[i]; + descr->virtual_address = sg_dma_address(sg_entry); + descr->length = sg_dma_len(sg_entry); + descr->memory_handle = 0; + total_length += sg_dma_len(sg_entry); + } + return total_length; +} + /** * map_sg_data: - Maps dma for a scatterlist and initializes decriptor fields * @cmd: Scsi_Cmnd with the scatterlist @@ -337,10 +382,11 @@ static void unmap_cmd_data(struct srp_cmd *cmd, struct device *dev) * Returns 1 on success. */ static int map_sg_data(struct scsi_cmnd *cmd, + struct srp_event_struct *evt_struct, struct srp_cmd *srp_cmd, struct device *dev) { - int i, sg_mapped; + int sg_mapped; u64 total_length = 0; struct scatterlist *sg = cmd->request_buffer; struct memory_descriptor *data = @@ -363,27 +409,46 @@ static int map_sg_data(struct scsi_cmnd *cmd, return 1; } - if (sg_mapped > MAX_INDIRECT_BUFS) { + if (sg_mapped > SG_ALL) { printk(KERN_ERR "ibmvscsi: More than %d mapped sg entries, got %d\n", - MAX_INDIRECT_BUFS, sg_mapped); + SG_ALL, sg_mapped); return 0; } indirect->head.virtual_address = 0; indirect->head.length = sg_mapped * sizeof(indirect->list[0]); indirect->head.memory_handle = 0; - for (i = 0; i < sg_mapped; ++i) { - struct memory_descriptor *descr = &indirect->list[i]; - struct scatterlist *sg_entry = &sg[i]; - descr->virtual_address = sg_dma_address(sg_entry); - descr->length = sg_dma_len(sg_entry); - descr->memory_handle = 0; - total_length += sg_dma_len(sg_entry); - } - indirect->total_length = total_length; - return 1; + if (sg_mapped <= MAX_INDIRECT_BUFS) { + total_length = map_sg_list(sg_mapped, sg, &indirect->list[0]); + indirect->total_length = total_length; + return 1; + } + + /* get indirect table */ + if (!evt_struct->ext_list) { + evt_struct->ext_list =(struct memory_descriptor*) + dma_alloc_coherent(dev, + SG_ALL * sizeof(struct memory_descriptor), + &evt_struct->ext_list_token, 0); + if (!evt_struct->ext_list) { + printk(KERN_ERR + "ibmvscsi: Can't allocate memory for indirect table\n"); + return 0; + + } + } + + total_length = map_sg_list(sg_mapped, sg, evt_struct->ext_list); + + indirect->total_length = total_length; + indirect->head.virtual_address = evt_struct->ext_list_token; + indirect->head.length = sg_mapped * sizeof(indirect->list[0]); + memcpy(indirect->list, evt_struct->ext_list, + MAX_INDIRECT_BUFS * sizeof(struct memory_descriptor)); + + return 1; } /** @@ -428,6 +493,7 @@ static int map_single_data(struct scsi_cmnd *cmd, * Returns 1 on success. */ static int map_data_for_srp_cmd(struct scsi_cmnd *cmd, + struct srp_event_struct *evt_struct, struct srp_cmd *srp_cmd, struct device *dev) { switch (cmd->sc_data_direction) { @@ -450,7 +516,7 @@ static int map_data_for_srp_cmd(struct scsi_cmnd *cmd, if (!cmd->request_buffer) return 1; if (cmd->use_sg) - return map_sg_data(cmd, srp_cmd, dev); + return map_sg_data(cmd, evt_struct, srp_cmd, dev); return map_single_data(cmd, srp_cmd, dev); } @@ -486,6 +552,7 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, printk(KERN_WARNING "ibmvscsi: Warning, request_limit exceeded\n"); unmap_cmd_data(&evt_struct->iu.srp.cmd, + evt_struct, hostdata->dev); free_event_struct(&hostdata->pool, evt_struct); return SCSI_MLQUEUE_HOST_BUSY; @@ -513,7 +580,7 @@ static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct, return 0; send_error: - unmap_cmd_data(&evt_struct->iu.srp.cmd, hostdata->dev); + unmap_cmd_data(&evt_struct->iu.srp.cmd, evt_struct, hostdata->dev); if ((cmnd = evt_struct->cmnd) != NULL) { cmnd->result = DID_ERROR << 16; @@ -551,6 +618,7 @@ static void handle_cmd_rsp(struct srp_event_struct *evt_struct) rsp->sense_and_response_data, rsp->sense_data_list_length); unmap_cmd_data(&evt_struct->iu.srp.cmd, + evt_struct, evt_struct->hostdata->dev); if (rsp->doover) @@ -583,6 +651,7 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd, { struct srp_cmd *srp_cmd; struct srp_event_struct *evt_struct; + struct indirect_descriptor *indirect; struct ibmvscsi_host_data *hostdata = (struct ibmvscsi_host_data *)&cmnd->device->host->hostdata; u16 lun = lun_from_dev(cmnd->device); @@ -591,6 +660,19 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd, if (!evt_struct) return SCSI_MLQUEUE_HOST_BUSY; + /* Set up the actual SRP IU */ + srp_cmd = &evt_struct->iu.srp.cmd; + memset(srp_cmd, 0x00, sizeof(*srp_cmd)); + srp_cmd->type = SRP_CMD_TYPE; + memcpy(srp_cmd->cdb, cmnd->cmnd, sizeof(cmnd->cmnd)); + srp_cmd->lun = ((u64) lun) << 48; + + if (!map_data_for_srp_cmd(cmnd, evt_struct, srp_cmd, hostdata->dev)) { + printk(KERN_ERR "ibmvscsi: couldn't convert cmd to srp_cmd\n"); + free_event_struct(&hostdata->pool, evt_struct); + return SCSI_MLQUEUE_HOST_BUSY; + } + init_event_struct(evt_struct, handle_cmd_rsp, VIOSRP_SRP_FORMAT, @@ -599,24 +681,11 @@ static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd, evt_struct->cmnd = cmnd; evt_struct->cmnd_done = done; - /* Set up the actual SRP IU */ - srp_cmd = &evt_struct->iu.srp.cmd; - memset(srp_cmd, 0x00, sizeof(*srp_cmd)); - srp_cmd->type = SRP_CMD_TYPE; - memcpy(srp_cmd->cdb, cmnd->cmnd, sizeof(cmnd->cmnd)); - srp_cmd->lun = ((u64) lun) << 48; - - if (!map_data_for_srp_cmd(cmnd, srp_cmd, hostdata->dev)) { - printk(KERN_ERR "ibmvscsi: couldn't convert cmd to srp_cmd\n"); - free_event_struct(&hostdata->pool, evt_struct); - return SCSI_MLQUEUE_HOST_BUSY; - } - /* Fix up dma address of the buffer itself */ - if ((srp_cmd->data_out_format == SRP_INDIRECT_BUFFER) || - (srp_cmd->data_in_format == SRP_INDIRECT_BUFFER)) { - struct indirect_descriptor *indirect = - (struct indirect_descriptor *)srp_cmd->additional_data; + indirect = (struct indirect_descriptor *)srp_cmd->additional_data; + if (((srp_cmd->data_out_format == SRP_INDIRECT_BUFFER) || + (srp_cmd->data_in_format == SRP_INDIRECT_BUFFER)) && + (indirect->head.virtual_address == 0)) { indirect->head.virtual_address = evt_struct->crq.IU_data_ptr + offsetof(struct srp_cmd, additional_data) + offsetof(struct indirect_descriptor, list); @@ -931,7 +1000,8 @@ static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd) cmd->result = (DID_ABORT << 16); list_del(&found_evt->list); - unmap_cmd_data(&found_evt->iu.srp.cmd, found_evt->hostdata->dev); + unmap_cmd_data(&found_evt->iu.srp.cmd, found_evt, + found_evt->hostdata->dev); free_event_struct(&found_evt->hostdata->pool, found_evt); spin_unlock_irqrestore(hostdata->host->host_lock, flags); atomic_inc(&hostdata->request_limit); @@ -1023,7 +1093,8 @@ static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd) if (tmp_evt->cmnd) tmp_evt->cmnd->result = (DID_RESET << 16); list_del(&tmp_evt->list); - unmap_cmd_data(&tmp_evt->iu.srp.cmd, tmp_evt->hostdata->dev); + unmap_cmd_data(&tmp_evt->iu.srp.cmd, tmp_evt, + tmp_evt->hostdata->dev); free_event_struct(&tmp_evt->hostdata->pool, tmp_evt); atomic_inc(&hostdata->request_limit); @@ -1052,6 +1123,7 @@ static void purge_requests(struct ibmvscsi_host_data *hostdata) if (tmp_evt->cmnd) { tmp_evt->cmnd->result = (DID_ERROR << 16); unmap_cmd_data(&tmp_evt->iu.srp.cmd, + tmp_evt, tmp_evt->hostdata->dev); if (tmp_evt->cmnd_done) tmp_evt->cmnd_done(tmp_evt->cmnd); @@ -1356,7 +1428,7 @@ static struct scsi_host_template driver_template = { .cmd_per_lun = 16, .can_queue = 1, /* Updated after SRP_LOGIN */ .this_id = -1, - .sg_tablesize = MAX_INDIRECT_BUFS, + .sg_tablesize = SG_ALL, .use_clustering = ENABLE_CLUSTERING, .shost_attrs = ibmvscsi_attrs, }; diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.h b/drivers/scsi/ibmvscsi/ibmvscsi.h index 1030b703c30e..8bec0438dc8a 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.h +++ b/drivers/scsi/ibmvscsi/ibmvscsi.h @@ -68,6 +68,8 @@ struct srp_event_struct { void (*cmnd_done) (struct scsi_cmnd *); struct completion comp; union viosrp_iu *sync_srp; + struct memory_descriptor *ext_list; + dma_addr_t ext_list_token; }; /* a pool of event structs for use */ From e47373ec1c9aab9ee134f4e2b8249957e9f4c7ef Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Wed, 30 Mar 2005 15:05:45 -0500 Subject: [PATCH 108/114] [SCSI] return success after retries in scsi_eh_tur The problem lies in the way the error handler uses TEST UNIT READY to tell whether error recovery has succeeded. The scsi_eh_tur function gives up after one round of retrying; after that it decides that more error recovery is needed. However TUR is liable to report sense data indicating a retry is needed when in fact error recovery has succeeded. A typical example might be SK=2, ASC=4, ASCQ=1 (Logical unit in process of becoming ready). The mere fact that we were able to get a sensible reply to the TUR should indicate that the device is working well enough to stop error recovery. I ran across a case back in January where this happened. A CD-ROM drive timed out the INQUIRY command, and a device reset fixed the blockage. But then the drive kept responding with 2/4/1 -- because it was spinning up I suppose -- until the error handler gave up and placed it offline. If the initial INQUIRY had received the 2/4/1 instead, everything would have worked okay. It doesn't seem reasonable for things to fail just because the error handler had started running. Signed-off-by: Alan Stern Signed-off-by: James Bottomley --- drivers/scsi/scsi_error.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index e9c451ba71fc..688bce740786 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -776,9 +776,11 @@ static int scsi_eh_tur(struct scsi_cmnd *scmd) __FUNCTION__, scmd, rtn)); if (rtn == SUCCESS) return 0; - else if (rtn == NEEDS_RETRY) + else if (rtn == NEEDS_RETRY) { if (retry_cnt--) goto retry_tur; + return 0; + } return 1; } From 4451e472627881e3e2240b224f127c99be500f91 Mon Sep 17 00:00:00 2001 From: Alan Stern Date: Tue, 12 Jul 2005 10:45:17 -0400 Subject: [PATCH 109/114] [SCSI] sd: pause in sd_spinup_disk for slow USB devices This patch adds a delay tailored for USB flash devices that are slow to initialize their firmware. The symptom is a repeated Unit Attention with ASC=0x28 (Not Ready to Ready transition). The patch will wait for up to 5 seconds for such devices to become ready. Normal devices won't send the repeated Unit Attention sense key and hence won't trigger the patch. This fixes a problem with James Roberts-Thomson's USB device, and I've seen several reports of other devices exhibiting the same symptoms -- presumably they will be helped as well. Signed-off-by: Alan Stern Signed-off-by: James Bottomley --- drivers/scsi/sd.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 0410e1bf109a..41ba0809f791 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -984,7 +984,7 @@ static void sd_spinup_disk(struct scsi_disk *sdkp, char *diskname, struct scsi_request *SRpnt, unsigned char *buffer) { unsigned char cmd[10]; - unsigned long spintime_value = 0; + unsigned long spintime_expire = 0; int retries, spintime; unsigned int the_result; struct scsi_sense_hdr sshdr; @@ -1071,12 +1071,27 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname, scsi_wait_req(SRpnt, (void *)cmd, (void *) buffer, 0/*512*/, SD_TIMEOUT, SD_MAX_RETRIES); - spintime_value = jiffies; + spintime_expire = jiffies + 100 * HZ; + spintime = 1; } - spintime = 1; /* Wait 1 second for next try */ msleep(1000); printk("."); + + /* + * Wait for USB flash devices with slow firmware. + * Yes, this sense key/ASC combination shouldn't + * occur here. It's characteristic of these devices. + */ + } else if (sense_valid && + sshdr.sense_key == UNIT_ATTENTION && + sshdr.asc == 0x28) { + if (!spintime) { + spintime_expire = jiffies + 5 * HZ; + spintime = 1; + } + /* Wait 1 second for next try */ + msleep(1000); } else { /* we don't understand the sense code, so it's * probably pointless to loop */ @@ -1088,8 +1103,7 @@ sd_spinup_disk(struct scsi_disk *sdkp, char *diskname, break; } - } while (spintime && - time_after(spintime_value + 100 * HZ, jiffies)); + } while (spintime && time_before_eq(jiffies, spintime_expire)); if (spintime) { if (scsi_status_is_good(the_result)) From 4869040512082b761de2d7c35975d01044f8bfea Mon Sep 17 00:00:00 2001 From: Anton Blanchard Date: Tue, 6 Sep 2005 18:08:14 +1000 Subject: [PATCH 110/114] [SCSI] Universal Xport no attach blacklist On Fri, Dec 13, 2002 at 12:24:39AM +1100, Anton Blanchard wrote: > We tested 2.5.51 on a ppc64 box, qlogic 2312 and a fastt700 array. I > had CONFIG_SCSI_REPORT_LUNS and unfortunately it thought the management > LUN was a disk: > > Vendor: IBM Model: Universal Xport Rev: 0520 > Type: Direct-Access ANSI SCSI revision: 03 > > ... > > SCSI device sdaj: drive cache: write through > SCSI device sdaj: 40960 512-byte hdwr sectors (21 MB) > sdaj: unknown partition table > Attached scsi disk sdaj at scsi2, channel 0, id 0, lun 31 > > ... > > end_request: I/O error, dev sdaj, sector 0 Three years later... It looks like SGI use the same FC vendor and they already have a workaround for this issue. The following patch adds the IBM version of it. Signed-off-by: Anton Blanchard Signed-off-by: James Bottomley --- drivers/scsi/scsi_devinfo.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index b444ec2e1c64..07b554affcf2 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -192,6 +192,7 @@ static struct { {"SGI", "RAID5", "*", BLIST_SPARSELUN}, {"SGI", "TP9100", "*", BLIST_REPORTLUN2}, {"SGI", "Universal Xport", "*", BLIST_NO_ULD_ATTACH}, + {"IBM", "Universal Xport", "*", BLIST_NO_ULD_ATTACH}, {"SMSC", "USB 2 HS-CF", NULL, BLIST_SPARSELUN | BLIST_INQUIRY_36}, {"SONY", "CD-ROM CDU-8001", NULL, BLIST_BORKEN}, {"SONY", "TSL", NULL, BLIST_FORCELUN}, /* DDS3 & DDS4 autoloaders */ From 32993523dc59759ae6cb349e4d231d4cd2165329 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 6 Sep 2005 14:03:44 +0200 Subject: [PATCH 111/114] [SCSI] fix SCSI_IOCTL_PROBE_HOST This returns always false with new-style drivers right now. Make it return always true instead, as a host must be present if we are able to call the ioctl (without a host attached there would be no device node to call on..) Signed-off-by: James Bottomley --- drivers/scsi/scsi_ioctl.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c index f5bf5c07be91..946c31fa6466 100644 --- a/drivers/scsi/scsi_ioctl.c +++ b/drivers/scsi/scsi_ioctl.c @@ -30,20 +30,20 @@ #define MAX_BUF PAGE_SIZE -/* - * If we are told to probe a host, we will return 0 if the host is not - * present, 1 if the host is present, and will return an identifying - * string at *arg, if arg is non null, filling to the length stored at - * (int *) arg +/** + * ioctl_probe -- return host identification + * @host: host to identify + * @buffer: userspace buffer for identification + * + * Return an identifying string at @buffer, if @buffer is non-NULL, filling + * to the length stored at * (int *) @buffer. */ - static int ioctl_probe(struct Scsi_Host *host, void __user *buffer) { unsigned int len, slen; const char *string; - int temp = host->hostt->present; - if (temp && buffer) { + if (buffer) { if (get_user(len, (unsigned int __user *) buffer)) return -EFAULT; @@ -59,7 +59,7 @@ static int ioctl_probe(struct Scsi_Host *host, void __user *buffer) return -EFAULT; } } - return temp; + return 1; } /* From c5478def7a3a2dba9ceda452c2aa3539514d30a9 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 6 Sep 2005 14:04:26 +0200 Subject: [PATCH 112/114] [SCSI] switch EH thread startup to the kthread API Signed-off-by: James Bottomley --- drivers/scsi/hosts.c | 23 ++++++++--------------- drivers/scsi/scsi_error.c | 29 ++--------------------------- include/scsi/scsi_host.h | 2 -- 3 files changed, 10 insertions(+), 44 deletions(-) diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 8640ad1c17e2..85503fad789a 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -225,15 +226,8 @@ static void scsi_host_dev_release(struct device *dev) struct Scsi_Host *shost = dev_to_shost(dev); struct device *parent = dev->parent; - if (shost->ehandler) { - DECLARE_COMPLETION(sem); - shost->eh_notify = &sem; - shost->eh_kill = 1; - up(shost->eh_wait); - wait_for_completion(&sem); - shost->eh_notify = NULL; - } - + if (shost->ehandler) + kthread_stop(shost->ehandler); if (shost->work_q) destroy_workqueue(shost->work_q); @@ -263,7 +257,6 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) { struct Scsi_Host *shost; int gfp_mask = GFP_KERNEL, rval; - DECLARE_COMPLETION(complete); if (sht->unchecked_isa_dma && privsize) gfp_mask |= __GFP_DMA; @@ -369,12 +362,12 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize) snprintf(shost->shost_classdev.class_id, BUS_ID_SIZE, "host%d", shost->host_no); - shost->eh_notify = &complete; - rval = kernel_thread(scsi_error_handler, shost, 0); - if (rval < 0) + shost->ehandler = kthread_run(scsi_error_handler, shost, + "scsi_eh_%d", shost->host_no); + if (IS_ERR(shost->ehandler)) { + rval = PTR_ERR(shost->ehandler); goto fail_destroy_freelist; - wait_for_completion(&complete); - shost->eh_notify = NULL; + } scsi_proc_hostdir_add(shost->hostt); return shost; diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 688bce740786..ebe74ccb518a 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -1585,16 +1586,8 @@ int scsi_error_handler(void *data) int rtn; DECLARE_MUTEX_LOCKED(sem); - /* - * Flush resources - */ - - daemonize("scsi_eh_%d", shost->host_no); - current->flags |= PF_NOFREEZE; - shost->eh_wait = &sem; - shost->ehandler = current; /* * Wake up the thread that created us. @@ -1602,8 +1595,6 @@ int scsi_error_handler(void *data) SCSI_LOG_ERROR_RECOVERY(3, printk("Wake up parent of" " scsi_eh_%d\n",shost->host_no)); - complete(shost->eh_notify); - while (1) { /* * If we get a signal, it means we are supposed to go @@ -1624,7 +1615,7 @@ int scsi_error_handler(void *data) * semaphores isn't unreasonable. */ down_interruptible(&sem); - if (shost->eh_kill) + if (kthread_should_stop()) break; SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler" @@ -1663,22 +1654,6 @@ int scsi_error_handler(void *data) * Make sure that nobody tries to wake us up again. */ shost->eh_wait = NULL; - - /* - * Knock this down too. From this point on, the host is flying - * without a pilot. If this is because the module is being unloaded, - * that's fine. If the user sent a signal to this thing, we are - * potentially in real danger. - */ - shost->eh_active = 0; - shost->ehandler = NULL; - - /* - * If anyone is waiting for us to exit (i.e. someone trying to unload - * a driver), then wake up that process to let them know we are on - * the way out the door. - */ - complete_and_exit(shost->eh_notify, 0); return 0; } diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index ac1b6125e3ae..916144be208b 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -467,12 +467,10 @@ struct Scsi_Host { struct task_struct * ehandler; /* Error recovery thread. */ struct semaphore * eh_wait; /* The error recovery thread waits on this. */ - struct completion * eh_notify; /* wait for eh to begin or end */ struct semaphore * eh_action; /* Wait for specific actions on the host. */ unsigned int eh_active:1; /* Indicates the eh thread is awake and active if this is true. */ - unsigned int eh_kill:1; /* set when killing the eh thread */ wait_queue_head_t host_wait; struct scsi_host_template *hostt; struct scsi_transport_template *transportt; From fe1b2d544d71300f8e2d151c3c77a130d13a58be Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 6 Sep 2005 14:15:37 +0200 Subject: [PATCH 113/114] [SCSI] unexport scsi_add_timer/scsi_delete_timer Signed-off-by: James Bottomley --- Documentation/scsi/scsi_mid_low_api.txt | 41 ------------------------- drivers/scsi/scsi_error.c | 2 -- drivers/scsi/scsi_priv.h | 3 ++ include/scsi/scsi_eh.h | 3 -- 4 files changed, 3 insertions(+), 46 deletions(-) diff --git a/Documentation/scsi/scsi_mid_low_api.txt b/Documentation/scsi/scsi_mid_low_api.txt index 7536823c0cb1..44df89c9c049 100644 --- a/Documentation/scsi/scsi_mid_low_api.txt +++ b/Documentation/scsi/scsi_mid_low_api.txt @@ -373,13 +373,11 @@ Summary: scsi_activate_tcq - turn on tag command queueing scsi_add_device - creates new scsi device (lu) instance scsi_add_host - perform sysfs registration and SCSI bus scan. - scsi_add_timer - (re-)start timer on a SCSI command. scsi_adjust_queue_depth - change the queue depth on a SCSI device scsi_assign_lock - replace default host_lock with given lock scsi_bios_ptable - return copy of block device's partition table scsi_block_requests - prevent further commands being queued to given host scsi_deactivate_tcq - turn off tag command queueing - scsi_delete_timer - cancel timer on a SCSI command. scsi_host_alloc - return a new scsi_host instance whose refcount==1 scsi_host_get - increments Scsi_Host instance's refcount scsi_host_put - decrements Scsi_Host instance's refcount (free if 0) @@ -457,27 +455,6 @@ struct scsi_device * scsi_add_device(struct Scsi_Host *shost, int scsi_add_host(struct Scsi_Host *shost, struct device * dev) -/** - * scsi_add_timer - (re-)start timer on a SCSI command. - * @scmd: pointer to scsi command instance - * @timeout: duration of timeout in "jiffies" - * @complete: pointer to function to call if timeout expires - * - * Returns nothing - * - * Might block: no - * - * Notes: Each scsi command has its own timer, and as it is added - * to the queue, we set up the timer. When the command completes, - * we cancel the timer. An LLD can use this function to change - * the existing timeout value. - * - * Defined in: drivers/scsi/scsi_error.c - **/ -void scsi_add_timer(struct scsi_cmnd *scmd, int timeout, - void (*complete)(struct scsi_cmnd *)) - - /** * scsi_adjust_queue_depth - allow LLD to change queue depth on a SCSI device * @sdev: pointer to SCSI device to change queue depth on @@ -565,24 +542,6 @@ void scsi_block_requests(struct Scsi_Host * shost) void scsi_deactivate_tcq(struct scsi_device *sdev, int depth) -/** - * scsi_delete_timer - cancel timer on a SCSI command. - * @scmd: pointer to scsi command instance - * - * Returns 1 if able to cancel timer else 0 (i.e. too late or already - * cancelled). - * - * Might block: no [may in the future if it invokes del_timer_sync()] - * - * Notes: All commands issued by upper levels already have a timeout - * associated with them. An LLD can use this function to cancel the - * timer. - * - * Defined in: drivers/scsi/scsi_error.c - **/ -int scsi_delete_timer(struct scsi_cmnd *scmd) - - /** * scsi_host_alloc - create a scsi host adapter instance and perform basic * initialization. diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index ebe74ccb518a..ae28bcb79242 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -116,7 +116,6 @@ void scsi_add_timer(struct scsi_cmnd *scmd, int timeout, add_timer(&scmd->eh_timeout); } -EXPORT_SYMBOL(scsi_add_timer); /** * scsi_delete_timer - Delete/cancel timer for a given function. @@ -144,7 +143,6 @@ int scsi_delete_timer(struct scsi_cmnd *scmd) return rtn; } -EXPORT_SYMBOL(scsi_delete_timer); /** * scsi_times_out - Timeout function for normal scsi commands. diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index d30d7f4e63ec..ee6de1768e53 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -63,6 +63,9 @@ extern int __init scsi_init_devinfo(void); extern void scsi_exit_devinfo(void); /* scsi_error.c */ +extern void scsi_add_timer(struct scsi_cmnd *, int, + void (*)(struct scsi_cmnd *)); +extern int scsi_delete_timer(struct scsi_cmnd *); extern void scsi_times_out(struct scsi_cmnd *cmd); extern int scsi_error_handler(void *host); extern int scsi_decide_disposition(struct scsi_cmnd *cmd); diff --git a/include/scsi/scsi_eh.h b/include/scsi/scsi_eh.h index 80557f879e3e..4b71095be681 100644 --- a/include/scsi/scsi_eh.h +++ b/include/scsi/scsi_eh.h @@ -27,9 +27,6 @@ struct scsi_sense_hdr { /* See SPC-3 section 4.5 */ }; -extern void scsi_add_timer(struct scsi_cmnd *, int, - void (*)(struct scsi_cmnd *)); -extern int scsi_delete_timer(struct scsi_cmnd *); extern void scsi_report_bus_reset(struct Scsi_Host *, int); extern void scsi_report_device_reset(struct Scsi_Host *, int, int); extern int scsi_block_when_processing_errors(struct scsi_device *); From 3173d8c342971a03857d8af749a3f57da7d06b57 Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sun, 4 Sep 2005 11:32:05 -0500 Subject: [PATCH 114/114] [SCSI] quieten messages on scsi_execute commands scsi_io_completion() can be a bit noisy about certain conditions. Previously this wasn't a problem for internally generated commands, since they never hit it. However, since we do all SCSI commands via bios, now they do. user CD testers like magicdev are now getting not ready messages every time they touch the CD to see if there's anything in it. Fix this by making all scsi_execute commands REQ_QUIET and making scsi_finish_io() not say anything for REQ_QUIET. Signed-off-by: James Bottomley --- drivers/scsi/scsi_lib.c | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 72a47ce7a1d3..77f2d444f7e0 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -315,7 +315,7 @@ int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd, req->sense = sense; req->sense_len = 0; req->timeout = timeout; - req->flags |= flags | REQ_BLOCK_PC | REQ_SPECIAL; + req->flags |= flags | REQ_BLOCK_PC | REQ_SPECIAL | REQ_QUIET; /* * head injection *required* here otherwise quiesce won't work @@ -927,17 +927,20 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes, scsi_requeue_command(q, cmd); return; } - printk(KERN_INFO "Device %s not ready.\n", - req->rq_disk ? req->rq_disk->disk_name : ""); + if (!(req->flags & REQ_QUIET)) + dev_printk(KERN_INFO, + &cmd->device->sdev_gendev, + "Device not ready.\n"); cmd = scsi_end_request(cmd, 0, this_count, 1); return; case VOLUME_OVERFLOW: - printk(KERN_INFO "Volume overflow <%d %d %d %d> CDB: ", - cmd->device->host->host_no, - (int)cmd->device->channel, - (int)cmd->device->id, (int)cmd->device->lun); - __scsi_print_command(cmd->data_cmnd); - scsi_print_sense("", cmd); + if (!(req->flags & REQ_QUIET)) { + dev_printk(KERN_INFO, + &cmd->device->sdev_gendev, + "Volume overflow, CDB: "); + __scsi_print_command(cmd->data_cmnd); + scsi_print_sense("", cmd); + } cmd = scsi_end_request(cmd, 0, block_bytes, 1); return; default: @@ -954,15 +957,13 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes, return; } if (result) { - if (!(req->flags & REQ_SPECIAL)) - printk(KERN_INFO "SCSI error : <%d %d %d %d> return code " - "= 0x%x\n", cmd->device->host->host_no, - cmd->device->channel, - cmd->device->id, - cmd->device->lun, result); + if (!(req->flags & REQ_QUIET)) { + dev_printk(KERN_INFO, &cmd->device->sdev_gendev, + "SCSI error: return code = 0x%x\n", result); - if (driver_byte(result) & DRIVER_SENSE) - scsi_print_sense("", cmd); + if (driver_byte(result) & DRIVER_SENSE) + scsi_print_sense("", cmd); + } /* * Mark a single buffer as not uptodate. Queue the remainder. * We sometimes get this cruft in the event that a medium error