From 389a588417f002e1b126f895342cc8b736e168fb Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Thu, 18 Jul 2002 06:11:48 -0700 Subject: [PATCH] Fix typo in net/sunrpc/xprt.c The appended patch fixes a typo in net/sunrpc/xprt.c: We want to ensure that we play safe, and only increment the UDP congestion window when we have successfully transmitted a full frame of data. In addition, we should perhaps still 'slow start' the UDP congestion code rather than assuming that we can immediately fire off 8 requests. IOW revert the value of RPC_INITCWND. --- include/linux/sunrpc/xprt.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 0a247f460ff7..eca42599039f 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -37,7 +37,7 @@ #define RPC_MAXREQS RPC_MAXCONG #define RPC_CWNDSCALE (256) #define RPC_MAXCWND (RPC_MAXCONG * RPC_CWNDSCALE) -#define RPC_INITCWND (RPC_MAXCWND >> 1) +#define RPC_INITCWND RPC_CWNDSCALE #define RPCXPRT_CONGESTED(xprt) ((xprt)->cong >= (xprt)->cwnd) /* Default timeout values */ -- cgit v1.2.3 From e18a7e5c12d40e8a9efce05b1f3f4a56dbc06917 Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Thu, 18 Jul 2002 19:06:32 -0700 Subject: [PATCH] MD - Get multipath to use mempool Get multipath to use mempool ... rather than maintaining it's own mempool --- drivers/md/multipath.c | 110 +++++++---------------------------------- include/linux/raid/multipath.h | 11 +---- 2 files changed, 19 insertions(+), 102 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index ba42b9b618a0..ad5e8199bb0c 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -58,87 +58,20 @@ struct multipath_bh *multipath_retry_list = NULL, **multipath_retry_tail; static int multipath_spare_write(mddev_t *, int); static int multipath_spare_active(mddev_t *mddev, mdp_disk_t **d); -static struct multipath_bh *multipath_alloc_mpbh(multipath_conf_t *conf) +static void *mp_pool_alloc(int gfp_flags, void *data) { - struct multipath_bh *mp_bh = NULL; - - do { - spin_lock_irq(&conf->device_lock); - if (!conf->freer1_blocked && conf->freer1) { - mp_bh = conf->freer1; - conf->freer1 = mp_bh->next_mp; - conf->freer1_cnt--; - mp_bh->next_mp = NULL; - mp_bh->state = (1 << MPBH_PreAlloc); - } - spin_unlock_irq(&conf->device_lock); - if (mp_bh) - return mp_bh; - mp_bh = (struct multipath_bh *) kmalloc(sizeof(struct multipath_bh), - GFP_NOIO); - if (mp_bh) { - memset(mp_bh, 0, sizeof(*mp_bh)); - return mp_bh; - } - conf->freer1_blocked = 1; - wait_disk_event(conf->wait_buffer, - !conf->freer1_blocked || - conf->freer1_cnt > NR_RESERVED_BUFS/2 - ); - conf->freer1_blocked = 0; - } while (1); + struct multipath_bh *mpb; + mpb = kmalloc(sizeof(*mpb), gfp_flags); + if (mpb) + memset(mpb, 0, sizeof(*mpb)); + return mpb; } -static inline void multipath_free_mpbh(struct multipath_bh *mp_bh) +static void mp_pool_free(void *mpb, void *data) { - multipath_conf_t *conf = mddev_to_conf(mp_bh->mddev); - - if (test_bit(MPBH_PreAlloc, &mp_bh->state)) { - unsigned long flags; - mp_bh->bio = NULL; - spin_lock_irqsave(&conf->device_lock, flags); - mp_bh->next_mp = conf->freer1; - conf->freer1 = mp_bh; - conf->freer1_cnt++; - spin_unlock_irqrestore(&conf->device_lock, flags); - wake_up(&conf->wait_buffer); - } else { - kfree(mp_bh); - } + kfree(mpb); } -static int multipath_grow_mpbh (multipath_conf_t *conf, int cnt) -{ - int i = 0; - - while (i < cnt) { - struct multipath_bh *mp_bh; - mp_bh = (struct multipath_bh*)kmalloc(sizeof(*mp_bh), GFP_KERNEL); - if (!mp_bh) - break; - memset(mp_bh, 0, sizeof(*mp_bh)); - set_bit(MPBH_PreAlloc, &mp_bh->state); - mp_bh->mddev = conf->mddev; - - multipath_free_mpbh(mp_bh); - i++; - } - return i; -} - -static void multipath_shrink_mpbh(multipath_conf_t *conf) -{ - spin_lock_irq(&conf->device_lock); - while (conf->freer1) { - struct multipath_bh *mp_bh = conf->freer1; - conf->freer1 = mp_bh->next_mp; - conf->freer1_cnt--; - kfree(mp_bh); - } - spin_unlock_irq(&conf->device_lock); -} - - static int multipath_map (mddev_t *mddev, struct block_device **bdev) { multipath_conf_t *conf = mddev_to_conf(mddev); @@ -185,10 +118,11 @@ static void multipath_reschedule_retry (struct multipath_bh *mp_bh) static void multipath_end_bh_io (struct multipath_bh *mp_bh, int uptodate) { struct bio *bio = mp_bh->master_bio; + multipath_conf_t *conf = mddev_to_conf(mp_bh->mddev); bio_endio(bio, uptodate); bio_put(mp_bh->bio); - multipath_free_mpbh(mp_bh); + mempool_free(mp_bh, conf->pool); } void multipath_end_request(struct bio *bio) @@ -251,7 +185,7 @@ static int multipath_make_request (request_queue_t *q, struct bio * bio) struct multipath_bh * mp_bh; struct multipath_info *multipath; - mp_bh = multipath_alloc_mpbh (conf); + mp_bh = mempool_alloc(conf->pool, GFP_NOIO); mp_bh->master_bio = bio; mp_bh->mddev = mddev; @@ -864,24 +798,15 @@ static int multipath_run (mddev_t *mddev) conf->mddev = mddev; conf->device_lock = SPIN_LOCK_UNLOCKED; - init_waitqueue_head(&conf->wait_buffer); - if (!conf->working_disks) { printk(NONE_OPERATIONAL, mdidx(mddev)); goto out_free_conf; } - - /* pre-allocate some buffer_head structures. - * As a minimum, 1 mpbh and raid_disks buffer_heads - * would probably get us by in tight memory situations, - * but a few more is probably a good idea. - * For now, try NR_RESERVED_BUFS mpbh and - * NR_RESERVED_BUFS*raid_disks bufferheads - * This will allow at least NR_RESERVED_BUFS concurrent - * reads or writes even if kmalloc starts failing - */ - if (multipath_grow_mpbh(conf, NR_RESERVED_BUFS) < NR_RESERVED_BUFS) { + conf->pool = mempool_create(NR_RESERVED_BUFS, + mp_pool_alloc, mp_pool_free, + NULL); + if (conf->pool == NULL) { printk(MEM_ERROR, mdidx(mddev)); goto out_free_conf; } @@ -916,7 +841,8 @@ static int multipath_run (mddev_t *mddev) return 0; out_free_conf: - multipath_shrink_mpbh(conf); + if (conf->pool) + mempool_destroy(conf->pool); kfree(conf); mddev->private = NULL; out: @@ -941,7 +867,7 @@ static int multipath_stop (mddev_t *mddev) multipath_conf_t *conf = mddev_to_conf(mddev); md_unregister_thread(conf->thread); - multipath_shrink_mpbh(conf); + mempool_destroy(conf->pool); kfree(conf); mddev->private = NULL; MOD_DEC_USE_COUNT; diff --git a/include/linux/raid/multipath.h b/include/linux/raid/multipath.h index e4f3e6189b7b..657eb913adba 100644 --- a/include/linux/raid/multipath.h +++ b/include/linux/raid/multipath.h @@ -27,16 +27,7 @@ struct multipath_private_data { struct multipath_info *spare; spinlock_t device_lock; - /* buffer pool */ - /* buffer_heads that we have pre-allocated have b_pprev -> &freebh - * and are linked into a stack using b_next - * multipath_bh that are pre-allocated have MPBH_PreAlloc set. - * All these variable are protected by device_lock - */ - struct multipath_bh *freer1; - int freer1_blocked; - int freer1_cnt; - wait_queue_head_t wait_buffer; + mempool_t *pool; }; typedef struct multipath_private_data multipath_conf_t; -- cgit v1.2.3 From 8e2a19e732d3d0f90cf425304c2c88c2b478db74 Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Thu, 18 Jul 2002 19:06:46 -0700 Subject: [PATCH] MD - 27 - Remove state field from multipath mp_bh structure. Remove state field from multipath mp_bh structure. The MPBH_Uptodate flag is set but never used, The MPBH_SyncPhase flag was never used. These a both legacy from the copying of raid1.c MPBH_PreAlloc is no longer needed as due to use of mempools, so the state field can go... --- drivers/md/multipath.c | 19 +------------------ include/linux/raid/multipath.h | 5 ----- 2 files changed, 1 insertion(+), 23 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index ad5e8199bb0c..3e05cfaa9153 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -130,24 +130,6 @@ void multipath_end_request(struct bio *bio) int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct multipath_bh * mp_bh = (struct multipath_bh *)(bio->bi_private); - /* - * this branch is our 'one multipath IO has finished' event handler: - */ - if (!uptodate) - md_error (mp_bh->mddev, bio->bi_bdev); - else - /* - * Set MPBH_Uptodate in our master buffer_head, so that - * we will return a good error code for to the higher - * levels even if IO on some other multipathed buffer fails. - * - * The 'master' represents the complex operation to - * user-side. So if something waits for IO, then it will - * wait for the 'master' buffer_head. - */ - set_bit (MPBH_Uptodate, &mp_bh->state); - - if (uptodate) { multipath_end_bh_io(mp_bh, uptodate); return; @@ -155,6 +137,7 @@ void multipath_end_request(struct bio *bio) /* * oops, IO error: */ + md_error (mp_bh->mddev, bio->bi_bdev); printk(KERN_ERR "multipath: %s: rescheduling sector %lu\n", bdev_partition_name(bio->bi_bdev), bio->bi_sector); multipath_reschedule_retry(mp_bh); diff --git a/include/linux/raid/multipath.h b/include/linux/raid/multipath.h index 657eb913adba..f34b54b83767 100644 --- a/include/linux/raid/multipath.h +++ b/include/linux/raid/multipath.h @@ -49,14 +49,9 @@ struct multipath_bh { * used from IRQ handlers */ int cmd; - unsigned long state; mddev_t *mddev; struct bio *master_bio; struct bio *bio; struct multipath_bh *next_mp; /* next for retry or in free list */ }; -/* bits for multipath_bh.state */ -#define MPBH_Uptodate 1 -#define MPBH_SyncPhase 2 -#define MPBH_PreAlloc 3 /* this was pre-allocated, add to free list */ #endif -- cgit v1.2.3 From e3de153e7a5c327619ea564046d937af5ae75924 Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Thu, 18 Jul 2002 19:07:01 -0700 Subject: [PATCH] MD - Embed bio in mp_bh rather than separate allocation. Embed bio in mp_bh rather than separate allocation. multipath currently allocates an mp_bh and a bio for each request. With this patch, the bio is made to be part of the mp_bh so there is only one allocation, and it from a private pool (the bio was allocated from a shared pool). Also remove "remaining" and "cmd" from mp_bh which aren't used. And remove spare (unused) from multipath_private_data. --- drivers/md/multipath.c | 18 +++++++----------- include/linux/raid/multipath.h | 10 +++------- 2 files changed, 10 insertions(+), 18 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index 3e05cfaa9153..7bc0662a6020 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -121,7 +121,6 @@ static void multipath_end_bh_io (struct multipath_bh *mp_bh, int uptodate) multipath_conf_t *conf = mddev_to_conf(mp_bh->mddev); bio_endio(bio, uptodate); - bio_put(mp_bh->bio); mempool_free(mp_bh, conf->pool); } @@ -164,7 +163,6 @@ static int multipath_make_request (request_queue_t *q, struct bio * bio) { mddev_t *mddev = q->queuedata; multipath_conf_t *conf = mddev_to_conf(mddev); - struct bio *real_bio; struct multipath_bh * mp_bh; struct multipath_info *multipath; @@ -172,20 +170,17 @@ static int multipath_make_request (request_queue_t *q, struct bio * bio) mp_bh->master_bio = bio; mp_bh->mddev = mddev; - mp_bh->cmd = bio_data_dir(bio); /* * read balancing logic: */ multipath = conf->multipaths + multipath_read_balance(conf); - real_bio = bio_clone(bio, GFP_NOIO); - real_bio->bi_bdev = multipath->bdev; - real_bio->bi_rw = bio_data_dir(bio); - real_bio->bi_end_io = multipath_end_request; - real_bio->bi_private = mp_bh; - mp_bh->bio = real_bio; - generic_make_request(real_bio); + mp_bh->bio = *bio; + mp_bh->bio.bi_bdev = multipath->bdev; + mp_bh->bio.bi_end_io = multipath_end_request; + mp_bh->bio.bi_private = mp_bh; + generic_make_request(&mp_bh->bio); return 0; } @@ -598,7 +593,8 @@ static void multipathd (void *data) printk(KERN_INFO "dirty sb detected, updating.\n"); md_update_sb(mddev); } - bio = mp_bh->bio; + bio = &mp_bh->bio; + bio->bi_sector = mp_bh->master_bio->bi_sector; bdev = bio->bi_bdev; multipath_map (mddev, &bio->bi_bdev); diff --git a/include/linux/raid/multipath.h b/include/linux/raid/multipath.h index f34b54b83767..886448c201fc 100644 --- a/include/linux/raid/multipath.h +++ b/include/linux/raid/multipath.h @@ -2,6 +2,7 @@ #define _MULTIPATH_H #include +#include struct multipath_info { int number; @@ -24,7 +25,6 @@ struct multipath_private_data { int raid_disks; int working_disks; mdk_thread_t *thread; - struct multipath_info *spare; spinlock_t device_lock; mempool_t *pool; @@ -45,13 +45,9 @@ typedef struct multipath_private_data multipath_conf_t; */ struct multipath_bh { - atomic_t remaining; /* 'have we finished' count, - * used from IRQ handlers - */ - int cmd; mddev_t *mddev; struct bio *master_bio; - struct bio *bio; - struct multipath_bh *next_mp; /* next for retry or in free list */ + struct bio bio; + struct multipath_bh *next_mp; /* next for retry */ }; #endif -- cgit v1.2.3 From a0f86742c04040981e3cb29439ca00179a15da0f Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Thu, 18 Jul 2002 19:07:27 -0700 Subject: [PATCH] MD - Use symbolic names for multipath (-4) and linear (-1) Use symbolic names for multipath (-4) and linear (-1) Also, a variable called "level" was being used to store a "level" and a "personality" number. This is potentially confusing, so it is now two variables. --- drivers/md/md.c | 28 ++++++++++++++-------------- drivers/md/multipath.c | 2 +- include/linux/raid/md_k.h | 11 +++++++---- 3 files changed, 22 insertions(+), 19 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/md.c b/drivers/md/md.c index e77d61646508..6eb566c0351f 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -1051,7 +1051,7 @@ static mdk_rdev_t *md_import_device(kdev_t newdev, int on_disk) goto abort_free; } - if (rdev->sb->level != -4) { + if (rdev->sb->level != LEVEL_MULTIPATH) { rdev->old_dev = mk_kdev(rdev->sb->this_disk.major, rdev->sb->this_disk.minor); rdev->desc_nr = rdev->sb->this_disk.number; @@ -1211,7 +1211,7 @@ static int analyze_sbs(mddev_t * mddev) * Fix up changed device names ... but only if this disk has a * recent update time. Use faulty checksum ones too. */ - if (mddev->sb->level != -4) + if (mddev->sb->level != LEVEL_MULTIPATH) ITERATE_RDEV(mddev,rdev,tmp) { __u64 ev1, ev2, ev3; if (rdev->faulty || rdev->alias_device) { @@ -1269,7 +1269,7 @@ static int analyze_sbs(mddev_t * mddev) * care if it was previously marked as faulty, it's up now * so enable it. */ - if (disk_faulty(desc) && mddev->sb->level != -4) { + if (disk_faulty(desc) && mddev->sb->level != LEVEL_MULTIPATH) { found = 0; ITERATE_RDEV(mddev,rdev,tmp) { if (rdev->desc_nr != desc->number) @@ -1312,7 +1312,7 @@ static int analyze_sbs(mddev_t * mddev) * we cannot check rdev->number. * We can check the device though. */ - if ((sb->level == -4) && + if ((sb->level == LEVEL_MULTIPATH) && kdev_same(rdev->dev, mk_kdev(desc->major,desc->minor))) { found = 1; @@ -1362,7 +1362,7 @@ static int analyze_sbs(mddev_t * mddev) * disk is which, only the position of the device * in the superblock: */ - if (mddev->sb->level == -4) { + if (mddev->sb->level == LEVEL_MULTIPATH) { if ((rdev->desc_nr != -1) && (rdev->desc_nr != i)) { MD_BUG(); goto abort; @@ -1387,7 +1387,7 @@ static int analyze_sbs(mddev_t * mddev) /* * Do a final reality check. */ - if (mddev->sb->level != -4) { + if (mddev->sb->level != LEVEL_MULTIPATH) { ITERATE_RDEV(mddev,rdev,tmp) { if (rdev->desc_nr == -1) { MD_BUG(); @@ -1473,7 +1473,7 @@ static int device_size_calculation(mddev_t * mddev) } switch (sb->level) { - case -4: + case LEVEL_MULTIPATH: data_disks = 1; break; case -3: @@ -1482,7 +1482,7 @@ static int device_size_calculation(mddev_t * mddev) case -2: data_disks = 1; break; - case -1: + case LEVEL_LINEAR: zoned_raid_size(mddev); data_disks = 1; break; @@ -3614,7 +3614,7 @@ static struct { */ static int __init md_setup(char *str) { - int minor, level, factor, fault; + int minor, level, factor, fault, pers; char *pername = ""; char *str1 = str; @@ -3631,7 +3631,7 @@ static int __init md_setup(char *str) } switch (get_option(&str, &level)) { /* RAID Personality */ case 2: /* could be 0 or -1.. */ - if (!level || level == -1) { + if (level == 0 || level == LEVEL_LINEAR) { if (get_option(&str, &factor) != 2 || /* Chunk Size */ get_option(&str, &fault) != 2) { printk(KERN_WARNING "md: Too few arguments supplied to md=.\n"); @@ -3640,12 +3640,12 @@ static int __init md_setup(char *str) md_setup_args.pers[minor] = level; md_setup_args.chunk[minor] = 1 << (factor+12); switch(level) { - case -1: - level = LINEAR; + case LEVEL_LINEAR: + pers = LINEAR; pername = "linear"; break; case 0: - level = RAID0; + pers = RAID0; pername = "raid0"; break; default: @@ -3654,7 +3654,7 @@ static int __init md_setup(char *str) level); return 0; } - md_setup_args.pers[minor] = level; + md_setup_args.pers[minor] = pers; break; } /* FALL THROUGH */ diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index 7bc0662a6020..7c3c1f4fb60b 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -665,7 +665,7 @@ static int multipath_run (mddev_t *mddev) MOD_INC_USE_COUNT; - if (sb->level != -4) { + if (sb->level != LEVEL_MULTIPATH) { printk(INVALID_LEVEL, mdidx(mddev), sb->level); goto out; } diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h index 2a9bbed805ad..c31bcc0ee766 100644 --- a/include/linux/raid/md_k.h +++ b/include/linux/raid/md_k.h @@ -25,13 +25,16 @@ #define MULTIPATH 7UL #define MAX_PERSONALITY 8UL +#define LEVEL_MULTIPATH (-4) +#define LEVEL_LINEAR (-1) + static inline int pers_to_level (int pers) { switch (pers) { - case MULTIPATH: return -4; + case MULTIPATH: return LEVEL_MULTIPATH; case HSM: return -3; case TRANSLUCENT: return -2; - case LINEAR: return -1; + case LINEAR: return LEVEL_LINEAR; case RAID0: return 0; case RAID1: return 1; case RAID5: return 5; @@ -43,10 +46,10 @@ static inline int pers_to_level (int pers) static inline int level_to_pers (int level) { switch (level) { - case -4: return MULTIPATH; + case LEVEL_MULTIPATH: return MULTIPATH; case -3: return HSM; case -2: return TRANSLUCENT; - case -1: return LINEAR; + case LEVEL_LINEAR: return LINEAR; case 0: return RAID0; case 1: return RAID1; case 4: -- cgit v1.2.3 From 2a9400e9457cb5bc2bb54c987f38b6f96fa5430e Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Thu, 18 Jul 2002 19:07:59 -0700 Subject: [PATCH] MD - Rdev list cleanups. Rdev list cleanups. An "rdev" can be on three different lists. - the list of all rdevs - the list of pending rdevs - the list of rdevs for a given mddev The first list is now only used to list "unused" devices in /proc/mdstat, and only pending rdevs can be unused, so this list isn't necessary. An rdev cannot be both pending and in an mddev, so we know rdev will only be on one list at at time. This patch discards the all_raid_disks list, and changes the pending list to use "same_set" in the rdev. It also changes /proc/mdstat to iterate through pending devices, rather than through all devices. So now an rdev is only on one list, either the pending list or the list of rdevs for a given mddev. This means that ITERATE_RDEV_GENERIC doesn't need to be told which field, to walk down: there is ony one. --- drivers/md/md.c | 44 +++++++++++++++----------------------------- include/linux/raid/md_k.h | 17 ++++------------- 2 files changed, 19 insertions(+), 42 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/md.c b/drivers/md/md.c index f81091c7a98e..8e2de784cd9e 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -550,7 +550,6 @@ static int match_mddev_units(mddev_t *mddev1, mddev_t *mddev2) return 0; } -static LIST_HEAD(all_raid_disks); static LIST_HEAD(pending_raid_disks); static void bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev) @@ -629,14 +628,9 @@ static void export_rdev(mdk_rdev_t * rdev) printk(KERN_INFO "md: export_rdev(%s)\n",partition_name(rdev->dev)); if (rdev->mddev) MD_BUG(); - unlock_rdev(rdev); free_disk_sb(rdev); - list_del_init(&rdev->all); - if (!list_empty(&rdev->pending)) { - printk(KERN_INFO "md: (%s was pending)\n", - partition_name(rdev->dev)); - list_del_init(&rdev->pending); - } + list_del_init(&rdev->same_set); + unlock_rdev(rdev); #ifndef MODULE md_autodetect_dev(rdev->dev); #endif @@ -1044,8 +1038,6 @@ static mdk_rdev_t *md_import_device(kdev_t newdev, int on_disk) rdev->desc_nr = -1; } } - list_add(&rdev->all, &all_raid_disks); - INIT_LIST_HEAD(&rdev->pending); INIT_LIST_HEAD(&rdev->same_set); if (rdev->faulty && rdev->sb) @@ -1821,7 +1813,7 @@ static void autorun_array(mddev_t *mddev) /* * lets try to run arrays based on all disks that have arrived - * until now. (those are in the ->pending list) + * until now. (those are in pending_raid_disks) * * the method: pick the first pending disk, collect all disks with * the same UUID, remove all from the pending list and put them into @@ -1841,7 +1833,7 @@ static void autorun_devices(void) printk(KERN_INFO "md: autorun ...\n"); while (!list_empty(&pending_raid_disks)) { rdev0 = list_entry(pending_raid_disks.next, - mdk_rdev_t, pending); + mdk_rdev_t, same_set); printk(KERN_INFO "md: considering %s ...\n", partition_name(rdev0->dev)); INIT_LIST_HEAD(&candidates); @@ -1854,8 +1846,7 @@ static void autorun_devices(void) continue; } printk(KERN_INFO "md: adding %s ...\n", partition_name(rdev->dev)); - list_del(&rdev->pending); - list_add(&rdev->pending, &candidates); + list_move(&rdev->same_set, &candidates); } } /* @@ -1878,9 +1869,9 @@ static void autorun_devices(void) mddev_unlock(mddev); } else { printk(KERN_INFO "md: created md%d\n", mdidx(mddev)); - ITERATE_RDEV_GENERIC(candidates,pending,rdev,tmp) { + ITERATE_RDEV_GENERIC(candidates,rdev,tmp) { + list_del_init(&rdev->same_set); bind_rdev_to_array(rdev, mddev); - list_del_init(&rdev->pending); } autorun_array(mddev); mddev_unlock(mddev); @@ -1888,7 +1879,7 @@ static void autorun_devices(void) /* on success, candidates will be empty, on error * it wont... */ - ITERATE_RDEV_GENERIC(candidates,pending,rdev,tmp) + ITERATE_RDEV_GENERIC(candidates,rdev,tmp) export_rdev(rdev); mddev_put(mddev); } @@ -1944,7 +1935,7 @@ static int autostart_array(kdev_t startdev) partition_name(startdev)); goto abort; } - list_add(&start_rdev->pending, &pending_raid_disks); + list_add(&start_rdev->same_set, &pending_raid_disks); sb = start_rdev->sb; @@ -1973,7 +1964,7 @@ static int autostart_array(kdev_t startdev) partition_name(dev)); continue; } - list_add(&rdev->pending, &pending_raid_disks); + list_add(&rdev->same_set, &pending_raid_disks); } /* @@ -2897,15 +2888,10 @@ static int status_unused(char * page) sz += sprintf(page + sz, "unused devices: "); - ITERATE_RDEV_ALL(rdev,tmp) { - if (list_empty(&rdev->same_set)) { - /* - * The device is not yet used by any array. - */ - i++; - sz += sprintf(page + sz, "%s ", - partition_name(rdev->dev)); - } + ITERATE_RDEV_PENDING(rdev,tmp) { + i++; + sz += sprintf(page + sz, "%s ", + partition_name(rdev->dev)); } if (!i) sz += sprintf(page + sz, ""); @@ -3556,7 +3542,7 @@ static void autostart_arrays(void) MD_BUG(); continue; } - list_add(&rdev->pending, &pending_raid_disks); + list_add(&rdev->same_set, &pending_raid_disks); } dev_cnt = 0; diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h index c31bcc0ee766..a59767eb6de7 100644 --- a/include/linux/raid/md_k.h +++ b/include/linux/raid/md_k.h @@ -143,8 +143,6 @@ static inline void mark_disk_nonsync(mdp_disk_t * d) struct mdk_rdev_s { struct list_head same_set; /* RAID devices within the same set */ - struct list_head all; /* all RAID devices */ - struct list_head pending; /* undetected RAID devices */ kdev_t dev; /* Device number */ kdev_t old_dev; /* "" when it was last imported */ @@ -239,30 +237,23 @@ extern mdp_disk_t *get_spare(mddev_t *mddev); * iterates through some rdev ringlist. It's safe to remove the * current 'rdev'. Dont touch 'tmp' though. */ -#define ITERATE_RDEV_GENERIC(head,field,rdev,tmp) \ +#define ITERATE_RDEV_GENERIC(head,rdev,tmp) \ \ for ((tmp) = (head).next; \ - (rdev) = (list_entry((tmp), mdk_rdev_t, field)), \ + (rdev) = (list_entry((tmp), mdk_rdev_t, same_set)), \ (tmp) = (tmp)->next, (tmp)->prev != &(head) \ ; ) /* * iterates through the 'same array disks' ringlist */ #define ITERATE_RDEV(mddev,rdev,tmp) \ - ITERATE_RDEV_GENERIC((mddev)->disks,same_set,rdev,tmp) - - -/* - * Iterates through all 'RAID managed disks' - */ -#define ITERATE_RDEV_ALL(rdev,tmp) \ - ITERATE_RDEV_GENERIC(all_raid_disks,all,rdev,tmp) + ITERATE_RDEV_GENERIC((mddev)->disks,rdev,tmp) /* * Iterates through 'pending RAID disks' */ #define ITERATE_RDEV_PENDING(rdev,tmp) \ - ITERATE_RDEV_GENERIC(pending_raid_disks,pending,rdev,tmp) + ITERATE_RDEV_GENERIC(pending_raid_disks,rdev,tmp) #define xchg_values(x,y) do { __typeof__(x) __tmp = x; \ x = y; y = __tmp; } while (0) -- cgit v1.2.3 From a15b60a21c12a15519d55b772a41d7710e200b49 Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Thu, 18 Jul 2002 19:08:13 -0700 Subject: [PATCH] MD - Pass the correct bdev to md_error Pass the correct bdev to md_error After a call to generic_make_request, bio->bi_bdev can have changed (e.g. by a re-mapped like raid0). So we cannot trust it for reporting the source of an error. This patch takes care to find the correct bdev. --- drivers/md/multipath.c | 12 ++++++++---- drivers/md/raid1.c | 39 +++++++++++++++++++++------------------ drivers/md/raid5.c | 4 ++-- include/linux/raid/multipath.h | 1 + 4 files changed, 32 insertions(+), 24 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index 7c3c1f4fb60b..7f6dd3ed27ae 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -128,7 +128,8 @@ void multipath_end_request(struct bio *bio) { int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); struct multipath_bh * mp_bh = (struct multipath_bh *)(bio->bi_private); - + multipath_conf_t *conf; + struct block_device *bdev; if (uptodate) { multipath_end_bh_io(mp_bh, uptodate); return; @@ -136,9 +137,11 @@ void multipath_end_request(struct bio *bio) /* * oops, IO error: */ - md_error (mp_bh->mddev, bio->bi_bdev); + conf = mddev_to_conf(mp_bh->mddev); + bdev = conf->multipaths[mp_bh->path].bdev; + md_error (mp_bh->mddev, bdev); printk(KERN_ERR "multipath: %s: rescheduling sector %lu\n", - bdev_partition_name(bio->bi_bdev), bio->bi_sector); + bdev_partition_name(bdev), bio->bi_sector); multipath_reschedule_retry(mp_bh); return; } @@ -174,7 +177,8 @@ static int multipath_make_request (request_queue_t *q, struct bio * bio) /* * read balancing logic: */ - multipath = conf->multipaths + multipath_read_balance(conf); + mp_bh->path = multipath_read_balance(conf); + multipath = conf->multipaths + mp_bh->path; mp_bh->bio = *bio; mp_bh->bio.bi_bdev = multipath->bdev; diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index caf5cd626095..05276fdf73a5 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -251,13 +251,21 @@ static void end_request(struct bio *bio) { int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private); - int i; - + int mirror; + conf_t *conf = mddev_to_conf(r1_bio->mddev); + + if (r1_bio->cmd == READ || r1_bio->cmd == READA) + mirror = r1_bio->read_disk; + else { + for (mirror = 0; mirror < MD_SB_DISKS; mirror++) + if (r1_bio->write_bios[mirror] == bio) + break; + } /* * this branch is our 'one mirror IO has finished' event handler: */ if (!uptodate) - md_error(r1_bio->mddev, bio->bi_bdev); + md_error(r1_bio->mddev, conf->mirrors[mirror].bdev); else /* * Set R1BIO_Uptodate in our master bio, so that @@ -270,10 +278,10 @@ static void end_request(struct bio *bio) */ set_bit(R1BIO_Uptodate, &r1_bio->state); + update_head_pos(mirror, r1_bio); if ((r1_bio->cmd == READ) || (r1_bio->cmd == READA)) { if (!r1_bio->read_bio) BUG(); - update_head_pos(r1_bio->read_disk, r1_bio); /* * we have only one bio on the read side */ @@ -295,14 +303,6 @@ static void end_request(struct bio *bio) /* * WRITE: * - * First, find the disk this bio belongs to. - */ - for (i = 0; i < MD_SB_DISKS; i++) - if (r1_bio->write_bios[i] == bio) { - update_head_pos(i, r1_bio); - break; - } - /* * Let's see if all mirrored write operations have finished * already. */ @@ -911,6 +911,7 @@ static void end_sync_read(struct bio *bio) { int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private); + conf_t *conf = mddev_to_conf(r1_bio->mddev); if (r1_bio->read_bio != bio) BUG(); @@ -921,7 +922,8 @@ static void end_sync_read(struct bio *bio) * We don't do much here, just schedule handling by raid1d */ if (!uptodate) - md_error (r1_bio->mddev, bio->bi_bdev); + md_error(r1_bio->mddev, + conf->mirrors[r1_bio->read_disk].bdev); else set_bit(R1BIO_Uptodate, &r1_bio->state); reschedule_retry(r1_bio); @@ -932,19 +934,20 @@ static void end_sync_write(struct bio *bio) int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); r1bio_t * r1_bio = (r1bio_t *)(bio->bi_private); mddev_t *mddev = r1_bio->mddev; + conf_t *conf = mddev_to_conf(mddev); int i; - - if (!uptodate) - md_error(mddev, bio->bi_bdev); + int mirror=0; for (i = 0; i < MD_SB_DISKS; i++) if (r1_bio->write_bios[i] == bio) { - update_head_pos(i, r1_bio); + mirror = i; break; } + if (!uptodate) + md_error(mddev, conf->mirrors[mirror].bdev); + update_head_pos(mirror, r1_bio); if (atomic_dec_and_test(&r1_bio->remaining)) { - conf_t *conf = mddev_to_conf(mddev); md_done_sync(mddev, r1_bio->master_bio->bi_size >> 9, uptodate); resume_device(conf); put_buf(r1_bio); diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 5d0af20344cc..44562157133b 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -371,7 +371,7 @@ static void raid5_end_read_request (struct bio * bi) set_bit(R5_UPTODATE, &sh->dev[i].flags); #endif } else { - md_error(conf->mddev, bi->bi_bdev); + md_error(conf->mddev, conf->disks[i].bdev); clear_bit(R5_UPTODATE, &sh->dev[i].flags); } #if 0 @@ -407,7 +407,7 @@ static void raid5_end_write_request (struct bio *bi) spin_lock_irqsave(&conf->device_lock, flags); if (!uptodate) - md_error(conf->mddev, bi->bi_bdev); + md_error(conf->mddev, conf->disks[i].bdev); clear_bit(R5_LOCKED, &sh->dev[i].flags); set_bit(STRIPE_HANDLE, &sh->state); diff --git a/include/linux/raid/multipath.h b/include/linux/raid/multipath.h index 886448c201fc..bd245bbcd845 100644 --- a/include/linux/raid/multipath.h +++ b/include/linux/raid/multipath.h @@ -48,6 +48,7 @@ struct multipath_bh { mddev_t *mddev; struct bio *master_bio; struct bio bio; + int path; struct multipath_bh *next_mp; /* next for retry */ }; #endif -- cgit v1.2.3 From 6f42312c7cd31635048afa10ad4dbce76a9dbe08 Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Thu, 18 Jul 2002 19:08:28 -0700 Subject: [PATCH] MD - Move md_update_sb calls Move md_update_sb calls When a change which requires a superblock update happens at interrupt time, we currently set a flag (sb_dirty) and wakeup to per-array thread (raid1/raid5d/multipathd) to do the actual update. This patch centralises this. The sb_update is now done by the mdrecoveryd thread. As this is always woken up after the error handler is called, we don't need the call to wakeup the local thread any more. With this, we don't need "md_update_sb" to lock the array any more and only use __md_update_sb which is local to md.c So we rename __md_update_sb back to md_update_sb and stop exporting it. --- drivers/md/md.c | 25 ++++++++----------------- drivers/md/multipath.c | 5 ----- drivers/md/raid1.c | 5 ----- drivers/md/raid5.c | 5 ----- include/linux/raid/md.h | 1 - 5 files changed, 8 insertions(+), 33 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/md.c b/drivers/md/md.c index 8e2de784cd9e..9ce7f9c1c6e8 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -904,7 +904,7 @@ static int sync_sbs(mddev_t * mddev) return 0; } -void __md_update_sb(mddev_t * mddev) +static void md_update_sb(mddev_t * mddev) { int err, count = 100; struct list_head *tmp; @@ -962,16 +962,6 @@ repeat: } } -void md_update_sb(mddev_t *mddev) -{ - if (mddev_lock(mddev)) - return; - if (mddev->sb_dirty) - __md_update_sb(mddev); - mddev_unlock(mddev); -} - - /* * Import a device. If 'on_disk', then sanity check the superblock * @@ -1640,7 +1630,7 @@ static int do_md_run(mddev_t * mddev) */ if (mddev->pers->sync_request) mddev->sb->state &= ~(1 << MD_SB_CLEAN); - __md_update_sb(mddev); + md_update_sb(mddev); md_recover_arrays(); /* @@ -1749,7 +1739,7 @@ static int do_md_stop(mddev_t * mddev, int ro) printk(KERN_INFO "md: marking sb clean...\n"); mddev->sb->state |= 1 << MD_SB_CLEAN; } - __md_update_sb(mddev); + md_update_sb(mddev); } if (ro) set_device_ro(dev, 1); @@ -2234,7 +2224,7 @@ static int hot_remove_disk(mddev_t * mddev, kdev_t dev) remove_descriptor(disk, mddev->sb); kick_rdev_from_array(rdev); - __md_update_sb(mddev); + md_update_sb(mddev); return 0; busy: @@ -2341,7 +2331,7 @@ static int hot_add_disk(mddev_t * mddev, kdev_t dev) mddev->sb->spare_disks++; mddev->sb->working_disks++; - __md_update_sb(mddev); + md_update_sb(mddev); /* * Kick recovery, maybe this spare has to be added to the @@ -3309,6 +3299,8 @@ void md_do_recovery(void *data) sb = mddev->sb; if (!sb || !mddev->pers || mddev->ro) goto unlock; + if (mddev->sb_dirty) + md_update_sb(mddev); if (mddev->recovery_running > 0) /* resync/recovery still happening */ goto unlock; @@ -3341,7 +3333,7 @@ void md_do_recovery(void *data) mddev->spare = NULL; } } - __md_update_sb(mddev); + md_update_sb(mddev); mddev->recovery_running = 0; wake_up(&resync_wait); goto unlock; @@ -3849,7 +3841,6 @@ EXPORT_SYMBOL(md_sync_acct); EXPORT_SYMBOL(md_done_sync); EXPORT_SYMBOL(md_register_thread); EXPORT_SYMBOL(md_unregister_thread); -EXPORT_SYMBOL(md_update_sb); EXPORT_SYMBOL(md_wakeup_thread); EXPORT_SYMBOL(md_print_devices); EXPORT_SYMBOL(find_rdev_nr); diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index 7f6dd3ed27ae..998048bc3966 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -226,7 +226,6 @@ static void mark_disk_bad (mddev_t *mddev, int failed) sb->working_disks--; sb->failed_disks++; mddev->sb_dirty = 1; - md_wakeup_thread(conf->thread); conf->working_disks--; printk (DISK_FAILED, bdev_partition_name (multipath->bdev), conf->working_disks); @@ -593,10 +592,6 @@ static void multipathd (void *data) spin_unlock_irqrestore(&retry_list_lock, flags); mddev = mp_bh->mddev; - if (mddev->sb_dirty) { - printk(KERN_INFO "dirty sb detected, updating.\n"); - md_update_sb(mddev); - } bio = &mp_bh->bio; bio->bi_sector = mp_bh->master_bio->bi_sector; bdev = bio->bi_bdev; diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 05276fdf73a5..f66146f099ad 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -586,7 +586,6 @@ static void mark_disk_bad(mddev_t *mddev, int failed) sb->working_disks--; sb->failed_disks++; mddev->sb_dirty = 1; - md_wakeup_thread(conf->thread); if (!mirror->write_only) conf->working_disks--; printk(DISK_FAILED, bdev_partition_name(mirror->bdev), conf->working_disks); @@ -1061,10 +1060,6 @@ static void raid1d(void *data) mddev = r1_bio->mddev; conf = mddev_to_conf(mddev); - if (mddev->sb_dirty) { - printk(KERN_INFO "raid1: dirty sb detected, updating.\n"); - md_update_sb(mddev); - } bio = r1_bio->master_bio; switch(r1_bio->cmd) { case SPECIAL: diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 44562157133b..d83a4155ab06 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -462,7 +462,6 @@ static int error(mddev_t *mddev, struct block_device *bdev) mddev->sb_dirty = 1; conf->working_disks--; conf->failed_disks++; - md_wakeup_thread(conf->thread); printk (KERN_ALERT "raid5: Disk failure on %s, disabling device." " Operation continuing on %d devices\n", @@ -494,7 +493,6 @@ static int error(mddev_t *mddev, struct block_device *bdev) sb->failed_disks++; mddev->sb_dirty = 1; - md_wakeup_thread(conf->thread); return 0; } @@ -1339,9 +1337,6 @@ static void raid5d (void *data) PRINTK("+++ raid5d active\n"); handled = 0; - - if (mddev->sb_dirty) - md_update_sb(mddev); spin_lock_irq(&conf->device_lock); while (1) { struct list_head *first; diff --git a/include/linux/raid/md.h b/include/linux/raid/md.h index 280092c6e95b..45aaf76dd768 100644 --- a/include/linux/raid/md.h +++ b/include/linux/raid/md.h @@ -75,7 +75,6 @@ extern mdk_thread_t * md_register_thread (void (*run) (void *data), extern void md_unregister_thread (mdk_thread_t *thread); extern void md_wakeup_thread(mdk_thread_t *thread); extern void md_interrupt_thread (mdk_thread_t *thread); -extern void md_update_sb (mddev_t *mddev); extern void md_done_sync(mddev_t *mddev, int blocks, int ok); extern void md_sync_acct(struct block_device *bdev, unsigned long nr_sectors); extern int md_error (mddev_t *mddev, struct block_device *bdev); -- cgit v1.2.3 From 03aa5c1c992f25689b3c2d548b8ce5f5050cdfa7 Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Thu, 18 Jul 2002 19:08:56 -0700 Subject: [PATCH] MD - Remove concept of 'spare' drive for multipath. Remove concept of 'spare' drive for multipath. Multipath now treats all working devices as active and does io to to first working one. --- drivers/md/multipath.c | 287 +++-------------------------------------- include/linux/raid/multipath.h | 1 - 2 files changed, 20 insertions(+), 268 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index 998048bc3966..7a3d233d4c8f 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -55,8 +55,6 @@ static mdk_personality_t multipath_personality; static spinlock_t retry_list_lock = SPIN_LOCK_UNLOCKED; struct multipath_bh *multipath_retry_list = NULL, **multipath_retry_tail; -static int multipath_spare_write(mddev_t *, int); -static int multipath_spare_active(mddev_t *mddev, mdp_disk_t **d); static void *mp_pool_alloc(int gfp_flags, void *data) { @@ -155,7 +153,7 @@ static int multipath_read_balance (multipath_conf_t *conf) { int disk; - for (disk = 0; disk < conf->raid_disks; disk++) + for (disk = 0; disk < MD_SB_DISKS; disk++) if (conf->multipaths[disk].operational) return disk; BUG(); @@ -239,20 +237,10 @@ static int multipath_error (mddev_t *mddev, struct block_device *bdev) multipath_conf_t *conf = mddev_to_conf(mddev); struct multipath_info * multipaths = conf->multipaths; int disks = MD_SB_DISKS; - int other_paths = 1; int i; - if (conf->working_disks == 1) { - other_paths = 0; - for (i = 0; i < disks; i++) { - if (multipaths[i].spare) { - other_paths = 1; - break; - } - } - } - if (!other_paths) { + if (conf->working_disks <= 1) { /* * Uh oh, we can do nothing if this is our last path, but * first check if this is a queued request for a device @@ -263,6 +251,7 @@ static int multipath_error (mddev_t *mddev, struct block_device *bdev) return 0; } printk (LAST_DISK); + return 1; /* leave it active... it's all we have */ } else { /* * Mark disk as unusable @@ -273,24 +262,6 @@ static int multipath_error (mddev_t *mddev, struct block_device *bdev) break; } } - if (!conf->working_disks) { - int err = 1; - mdp_disk_t *spare; - mdp_super_t *sb = mddev->sb; - - spare = get_spare(mddev); - if (spare) { - err = multipath_spare_write(mddev, spare->number); - printk("got DISKOP_SPARE_WRITE err: %d. (spare_faulty(): %d)\n", err, disk_faulty(spare)); - } - if (!err && !disk_faulty(spare)) { - multipath_spare_active(mddev, &spare); - mark_disk_sync(spare); - mark_disk_active(spare); - sb->active_disks++; - sb->spare_disks--; - } - } } return 0; } @@ -315,183 +286,15 @@ static void print_multipath_conf (multipath_conf_t *conf) for (i = 0; i < MD_SB_DISKS; i++) { tmp = conf->multipaths + i; - if (tmp->spare || tmp->operational || tmp->number || + if (tmp->operational || tmp->number || tmp->raid_disk || tmp->used_slot) - printk(" disk%d, s:%d, o:%d, n:%d rd:%d us:%d dev:%s\n", - i, tmp->spare,tmp->operational, + printk(" disk%d, o:%d, n:%d rd:%d us:%d dev:%s\n", + i,tmp->operational, tmp->number,tmp->raid_disk,tmp->used_slot, bdev_partition_name(tmp->bdev)); } } -/* - * Find the spare disk ... (can only be in the 'high' area of the array) - */ -static struct multipath_info *find_spare(mddev_t *mddev, int number) -{ - multipath_conf_t *conf = mddev->private; - int i; - for (i = conf->raid_disks; i < MD_SB_DISKS; i++) { - struct multipath_info *p = conf->multipaths + i; - if (p->spare && p->number == number) - return p; - } - return NULL; -} - -static int multipath_spare_inactive(mddev_t *mddev) -{ - multipath_conf_t *conf = mddev->private; - struct multipath_info *p; - int err = 0; - - print_multipath_conf(conf); - spin_lock_irq(&conf->device_lock); - p = find_spare(mddev, mddev->spare->number); - if (p) { - p->operational = 0; - } else { - MD_BUG(); - err = 1; - } - spin_unlock_irq(&conf->device_lock); - - print_multipath_conf(conf); - return err; -} - -static int multipath_spare_write(mddev_t *mddev, int number) -{ - multipath_conf_t *conf = mddev->private; - struct multipath_info *p; - int err = 0; - - print_multipath_conf(conf); - spin_lock_irq(&conf->device_lock); - p = find_spare(mddev, number); - if (p) { - p->operational = 1; - } else { - MD_BUG(); - err = 1; - } - spin_unlock_irq(&conf->device_lock); - - print_multipath_conf(conf); - return err; -} - -static int multipath_spare_active(mddev_t *mddev, mdp_disk_t **d) -{ - int err = 0; - int i, failed_disk=-1, spare_disk=-1; - multipath_conf_t *conf = mddev->private; - struct multipath_info *tmp, *sdisk, *fdisk; - mdp_super_t *sb = mddev->sb; - mdp_disk_t *failed_desc, *spare_desc; - mdk_rdev_t *spare_rdev, *failed_rdev; - - print_multipath_conf(conf); - spin_lock_irq(&conf->device_lock); - /* - * Find the failed disk within the MULTIPATH configuration ... - * (this can only be in the first conf->working_disks part) - */ - for (i = 0; i < conf->raid_disks; i++) { - tmp = conf->multipaths + i; - if ((!tmp->operational && !tmp->spare) || - !tmp->used_slot) { - failed_disk = i; - break; - } - } - /* - * When we activate a spare disk we _must_ have a disk in - * the lower (active) part of the array to replace. - */ - if (failed_disk == -1) { - MD_BUG(); - err = 1; - goto abort; - } - /* - * Find the spare disk ... (can only be in the 'high' - * area of the array) - */ - for (i = conf->raid_disks; i < MD_SB_DISKS; i++) { - tmp = conf->multipaths + i; - if (tmp->spare && tmp->number == (*d)->number) { - spare_disk = i; - break; - } - } - if (spare_disk == -1) { - MD_BUG(); - err = 1; - goto abort; - } - - sdisk = conf->multipaths + spare_disk; - fdisk = conf->multipaths + failed_disk; - - spare_desc = &sb->disks[sdisk->number]; - failed_desc = &sb->disks[fdisk->number]; - - if (spare_desc != *d || spare_desc->raid_disk != sdisk->raid_disk || - sdisk->raid_disk != spare_disk || fdisk->raid_disk != failed_disk || - failed_desc->raid_disk != fdisk->raid_disk) { - MD_BUG(); - err = 1; - goto abort; - } - - /* - * do the switch finally - */ - spare_rdev = find_rdev_nr(mddev, spare_desc->number); - failed_rdev = find_rdev_nr(mddev, failed_desc->number); - xchg_values(spare_rdev->desc_nr, failed_rdev->desc_nr); - spare_rdev->alias_device = 0; - failed_rdev->alias_device = 1; - - xchg_values(*spare_desc, *failed_desc); - xchg_values(*fdisk, *sdisk); - - /* - * (careful, 'failed' and 'spare' are switched from now on) - * - * we want to preserve linear numbering and we want to - * give the proper raid_disk number to the now activated - * disk. (this means we switch back these values) - */ - - xchg_values(spare_desc->raid_disk, failed_desc->raid_disk); - xchg_values(sdisk->raid_disk, fdisk->raid_disk); - xchg_values(spare_desc->number, failed_desc->number); - xchg_values(sdisk->number, fdisk->number); - - *d = failed_desc; - - if (!sdisk->bdev) - sdisk->used_slot = 0; - /* - * this really activates the spare. - */ - fdisk->spare = 0; - - /* - * if we activate a spare, we definitely replace a - * non-operational disk slot in the 'low' area of - * the disk array. - */ - - conf->working_disks++; -abort: - spin_unlock_irq(&conf->device_lock); - - print_multipath_conf(conf); - return err; -} static int multipath_add_disk(mddev_t *mddev, mdp_disk_t *added_desc, mdk_rdev_t *rdev) @@ -502,7 +305,7 @@ static int multipath_add_disk(mddev_t *mddev, mdp_disk_t *added_desc, print_multipath_conf(conf); spin_lock_irq(&conf->device_lock); - for (i = conf->raid_disks; i < MD_SB_DISKS; i++) { + for (i = 0; i < MD_SB_DISKS; i++) { struct multipath_info *p = conf->multipaths + i; if (!p->used_slot) { if (added_desc->number != i) @@ -510,10 +313,10 @@ static int multipath_add_disk(mddev_t *mddev, mdp_disk_t *added_desc, p->number = added_desc->number; p->raid_disk = added_desc->raid_disk; p->bdev = rdev->bdev; - p->operational = 0; - p->spare = 1; + p->operational = 1; p->used_slot = 1; conf->nr_disks++; + conf->working_disks++; err = 0; break; } @@ -543,8 +346,6 @@ static int multipath_remove_disk(mddev_t *mddev, int number) err = -EBUSY; goto abort; } - if (p->spare && i < conf->raid_disks) - break; p->bdev = NULL; p->used_slot = 0; conf->nr_disks--; @@ -655,10 +456,10 @@ static int multipath_run (mddev_t *mddev) { multipath_conf_t *conf; int i, j, disk_idx; - struct multipath_info *disk, *disk2; + struct multipath_info *disk; mdp_super_t *sb = mddev->sb; - mdp_disk_t *desc, *desc2; - mdk_rdev_t *rdev, *def_rdev = NULL; + mdp_disk_t *desc; + mdk_rdev_t *rdev; struct list_head *tmp; int num_rdevs = 0; @@ -709,69 +510,24 @@ static int multipath_run (mddev_t *mddev) printk(NOT_IN_SYNC, bdev_partition_name(rdev->bdev)); /* - * Mark all disks as spare to start with, then pick our - * active disk. If we have a disk that is marked active - * in the sb, then use it, else use the first rdev. + * Mark all disks as active to start with, there are no + * spares. multipath_read_balance deals with choose + * the "best" operational device. */ disk->number = desc->number; disk->raid_disk = desc->raid_disk; disk->bdev = rdev->bdev; - disk->operational = 0; - disk->spare = 1; + disk->operational = 1; disk->used_slot = 1; mark_disk_sync(desc); - - if (disk_active(desc)) { - if(!conf->working_disks) { - printk(OPERATIONAL, bdev_partition_name(rdev->bdev), - desc->raid_disk); - disk->operational = 1; - disk->spare = 0; - conf->working_disks++; - def_rdev = rdev; - } else { - mark_disk_spare(desc); - } - } else - mark_disk_spare(desc); - - if(!num_rdevs++) def_rdev = rdev; - } - if(!conf->working_disks && num_rdevs) { - desc = &sb->disks[def_rdev->desc_nr]; - disk = conf->multipaths + desc->raid_disk; - printk(OPERATIONAL, bdev_partition_name(def_rdev->bdev), - disk->raid_disk); - disk->operational = 1; - disk->spare = 0; - conf->working_disks++; mark_disk_active(desc); + num_rdevs++; } - /* - * Make sure our active path is in desc spot 0 - */ - if(def_rdev->desc_nr != 0) { - rdev = find_rdev_nr(mddev, 0); - desc = &sb->disks[def_rdev->desc_nr]; - desc2 = sb->disks; - disk = conf->multipaths + desc->raid_disk; - disk2 = conf->multipaths + desc2->raid_disk; - xchg_values(*desc2,*desc); - xchg_values(*disk2,*disk); - xchg_values(desc2->number, desc->number); - xchg_values(disk2->number, disk->number); - xchg_values(desc2->raid_disk, desc->raid_disk); - xchg_values(disk2->raid_disk, disk->raid_disk); - if(rdev) { - xchg_values(def_rdev->desc_nr,rdev->desc_nr); - } else { - def_rdev->desc_nr = 0; - } - } - conf->raid_disks = sb->raid_disks = sb->active_disks = 1; + + conf->raid_disks = sb->raid_disks = sb->active_disks = num_rdevs; conf->nr_disks = sb->nr_disks = sb->working_disks = num_rdevs; sb->failed_disks = 0; - sb->spare_disks = num_rdevs - 1; + sb->spare_disks = 0; mddev->sb_dirty = 1; conf->mddev = mddev; conf->device_lock = SPIN_LOCK_UNLOCKED; @@ -862,9 +618,6 @@ static mdk_personality_t multipath_personality= error_handler: multipath_error, hot_add_disk: multipath_add_disk, hot_remove_disk:multipath_remove_disk, - spare_inactive: multipath_spare_inactive, - spare_active: multipath_spare_active, - spare_write: multipath_spare_write, }; static int __init multipath_init (void) diff --git a/include/linux/raid/multipath.h b/include/linux/raid/multipath.h index bd245bbcd845..4b7e3c0dc792 100644 --- a/include/linux/raid/multipath.h +++ b/include/linux/raid/multipath.h @@ -13,7 +13,6 @@ struct multipath_info { * State bits: */ int operational; - int spare; int used_slot; }; -- cgit v1.2.3 From 82081640182e42249dfada1c5010d78ba168804a Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Thu, 18 Jul 2002 19:09:07 -0700 Subject: [PATCH] MD - Improve handling of spares in md Improve handling of spares in md - hot_remove_disk is given the raid_disk rather than descriptor number so that it can find the device in internal array directly, no search. - spare_inactive now uses mddev->spare->raid_disk instead of mddev->spare->number so it can find the device directly without searching - spare_write does not need number. It can use mddev->spare->raid_disk as above. - spare_active does not need &mddev->spare. It finds the descriptor directly and fixes it without this pointer --- drivers/md/md.c | 8 +++---- drivers/md/multipath.c | 24 ++++++++----------- drivers/md/raid1.c | 61 ++++++++++++----------------------------------- drivers/md/raid5.c | 59 +++++++++++---------------------------------- include/linux/raid/md_k.h | 4 ++-- 5 files changed, 44 insertions(+), 112 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/md.c b/drivers/md/md.c index 8187e0464488..04d44dd199cf 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -2202,7 +2202,7 @@ static int hot_remove_disk(mddev_t * mddev, kdev_t dev) return -EINVAL; } - err = mddev->pers->hot_remove_disk(mddev, disk->number); + err = mddev->pers->hot_remove_disk(mddev, disk->raid_disk); if (err == -EBUSY) { MD_BUG(); goto busy; @@ -3314,8 +3314,7 @@ void md_do_recovery(void *data) goto unlock; /* success...*/ if (mddev->spare) { - mddev->pers->spare_active(mddev, - &mddev->spare); + mddev->pers->spare_active(mddev); mark_disk_sync(mddev->spare); mark_disk_active(mddev->spare); sb->active_disks++; @@ -3359,8 +3358,7 @@ void md_do_recovery(void *data) mddev->recovery_running = 0; } else { if (mddev->spare) - mddev->pers->spare_write(mddev, - mddev->spare->number); + mddev->pers->spare_write(mddev); mddev->recovery_running = 1; md_wakeup_thread(mddev->sync_thread); } diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index 7a3d233d4c8f..c201fda0189d 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -333,25 +333,21 @@ static int multipath_remove_disk(mddev_t *mddev, int number) { multipath_conf_t *conf = mddev->private; int err = 1; - int i; + struct multipath_info *p = conf->multipaths + number; print_multipath_conf(conf); spin_lock_irq(&conf->device_lock); - for (i = 0; i < MD_SB_DISKS; i++) { - struct multipath_info *p = conf->multipaths + i; - if (p->used_slot && (p->number == number)) { - if (p->operational) { - printk(KERN_ERR "hot-remove-disk, slot %d is identified to be the requested disk (number %d), but is still operational!\n", i, number); - err = -EBUSY; - goto abort; - } - p->bdev = NULL; - p->used_slot = 0; - conf->nr_disks--; - err = 0; - break; + if (p->used_slot) { + if (p->operational) { + printk(KERN_ERR "hot-remove-disk, slot %d is identified but is still operational!\n", number); + err = -EBUSY; + goto abort; } + p->bdev = NULL; + p->used_slot = 0; + conf->nr_disks--; + err = 0; } if (err) MD_BUG(); diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index f66146f099ad..91238ae3c2bc 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -657,19 +657,7 @@ static void close_sync(conf_t *conf) conf->r1buf_pool = NULL; } -static mirror_info_t *find_spare(mddev_t *mddev, int number) -{ - conf_t *conf = mddev->private; - int i; - for (i = conf->raid_disks; i < MD_SB_DISKS; i++) { - mirror_info_t *p = conf->mirrors + i; - if (p->spare && p->number == number) - return p; - } - return NULL; -} - -static int raid1_spare_active(mddev_t *mddev, mdp_disk_t **d) +static int raid1_spare_active(mddev_t *mddev) { int err = 0; int i, failed_disk = -1, spare_disk = -1; @@ -706,18 +694,7 @@ static int raid1_spare_active(mddev_t *mddev, mdp_disk_t **d) * Find the spare disk ... (can only be in the 'high' * area of the array) */ - for (i = conf->raid_disks; i < MD_SB_DISKS; i++) { - tmp = conf->mirrors + i; - if (tmp->spare && tmp->number == (*d)->number) { - spare_disk = i; - break; - } - } - if (spare_disk == -1) { - MD_BUG(); - err = 1; - goto abort; - } + spare_disk = mddev->spare->raid_disk; sdisk = conf->mirrors + spare_disk; fdisk = conf->mirrors + failed_disk; @@ -725,7 +702,7 @@ static int raid1_spare_active(mddev_t *mddev, mdp_disk_t **d) spare_desc = &sb->disks[sdisk->number]; failed_desc = &sb->disks[fdisk->number]; - if (spare_desc != *d || spare_desc->raid_disk != sdisk->raid_disk || + if (spare_desc->raid_disk != sdisk->raid_disk || sdisk->raid_disk != spare_disk || fdisk->raid_disk != failed_disk || failed_desc->raid_disk != fdisk->raid_disk) { MD_BUG(); @@ -762,8 +739,6 @@ static int raid1_spare_active(mddev_t *mddev, mdp_disk_t **d) xchg_values(spare_desc->number, failed_desc->number); xchg_values(sdisk->number, fdisk->number); - *d = failed_desc; - if (!sdisk->bdev) sdisk->used_slot = 0; /* @@ -794,7 +769,7 @@ static int raid1_spare_inactive(mddev_t *mddev) print_conf(conf); spin_lock_irq(&conf->device_lock); - p = find_spare(mddev, mddev->spare->number); + p = conf->mirrors + mddev->spare->raid_disk; if (p) { p->operational = 0; p->write_only = 0; @@ -807,7 +782,7 @@ static int raid1_spare_inactive(mddev_t *mddev) return err; } -static int raid1_spare_write(mddev_t *mddev, int number) +static int raid1_spare_write(mddev_t *mddev) { conf_t *conf = mddev->private; mirror_info_t *p; @@ -815,7 +790,7 @@ static int raid1_spare_write(mddev_t *mddev, int number) print_conf(conf); spin_lock_irq(&conf->device_lock); - p = find_spare(mddev, number); + p = conf->mirrors + mddev->spare->raid_disk; if (p) { p->operational = 1; p->write_only = 1; @@ -871,25 +846,19 @@ static int raid1_remove_disk(mddev_t *mddev, int number) { conf_t *conf = mddev->private; int err = 1; - int i; + mirror_info_t *p = conf->mirrors+ number; print_conf(conf); spin_lock_irq(&conf->device_lock); - for (i = 0; i < MD_SB_DISKS; i++) { - mirror_info_t *p = conf->mirrors + i; - if (p->used_slot && (p->number == number)) { - if (p->operational) { - err = -EBUSY; - goto abort; - } - if (p->spare && (i < conf->raid_disks)) - break; - p->bdev = NULL; - p->used_slot = 0; - conf->nr_disks--; - err = 0; - break; + if (p->used_slot) { + if (p->operational) { + err = -EBUSY; + goto abort; } + p->bdev = NULL; + p->used_slot = 0; + conf->nr_disks--; + err = 0; } if (err) MD_BUG(); diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index d83a4155ab06..a4c9d407ddc1 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -1686,19 +1686,7 @@ static void print_raid5_conf (raid5_conf_t *conf) } } -static struct disk_info *find_spare(mddev_t *mddev, int number) -{ - raid5_conf_t *conf = mddev->private; - int i; - for (i = conf->raid_disks; i < MD_SB_DISKS; i++) { - struct disk_info *p = conf->disks + i; - if (p->spare && p->number == number) - return p; - } - return NULL; -} - -static int raid5_spare_active(mddev_t *mddev, mdp_disk_t **d) +static int raid5_spare_active(mddev_t *mddev) { int err = 0; int i, failed_disk=-1, spare_disk=-1; @@ -1727,18 +1715,7 @@ static int raid5_spare_active(mddev_t *mddev, mdp_disk_t **d) * Find the spare disk ... (can only be in the 'high' * area of the array) */ - for (i = conf->raid_disks; i < MD_SB_DISKS; i++) { - tmp = conf->disks + i; - if (tmp->spare && tmp->number == (*d)->number) { - spare_disk = i; - break; - } - } - if (spare_disk == -1) { - MD_BUG(); - err = 1; - goto abort; - } + spare_disk = mddev->spare->raid_disk; if (!conf->spare) { MD_BUG(); @@ -1751,7 +1728,7 @@ static int raid5_spare_active(mddev_t *mddev, mdp_disk_t **d) spare_desc = &sb->disks[sdisk->number]; failed_desc = &sb->disks[fdisk->number]; - if (spare_desc != *d || spare_desc->raid_disk != sdisk->raid_disk || + if ( spare_desc->raid_disk != sdisk->raid_disk || sdisk->raid_disk != spare_disk || fdisk->raid_disk != failed_disk || failed_desc->raid_disk != fdisk->raid_disk) { MD_BUG(); @@ -1788,8 +1765,6 @@ static int raid5_spare_active(mddev_t *mddev, mdp_disk_t **d) xchg_values(spare_desc->number, failed_desc->number); xchg_values(sdisk->number, fdisk->number); - *d = failed_desc; - if (!sdisk->bdev) sdisk->used_slot = 0; @@ -1821,7 +1796,7 @@ static int raid5_spare_inactive(mddev_t *mddev) print_raid5_conf(conf); spin_lock_irq(&conf->device_lock); - p = find_spare(mddev, mddev->spare->number); + p = conf->disks + mddev->spare->raid_disk; if (p) { p->operational = 0; p->write_only = 0; @@ -1836,7 +1811,7 @@ static int raid5_spare_inactive(mddev_t *mddev) return err; } -static int raid5_spare_write(mddev_t *mddev, int number) +static int raid5_spare_write(mddev_t *mddev) { raid5_conf_t *conf = mddev->private; struct disk_info *p; @@ -1844,7 +1819,7 @@ static int raid5_spare_write(mddev_t *mddev, int number) print_raid5_conf(conf); spin_lock_irq(&conf->device_lock); - p = find_spare(mddev, number); + p = conf->disks + mddev->spare->raid_disk; if (p && !conf->spare) { p->operational = 1; p->write_only = 1; @@ -1862,25 +1837,19 @@ static int raid5_remove_disk(mddev_t *mddev, int number) { raid5_conf_t *conf = mddev->private; int err = 1; - int i; + struct disk_info *p = conf->disks + number; print_raid5_conf(conf); spin_lock_irq(&conf->device_lock); - for (i = 0; i < MD_SB_DISKS; i++) { - struct disk_info *p = conf->disks + i; - if (p->used_slot && p->number == number) { - if (p->operational) { - err = -EBUSY; - goto abort; - } - if (p->spare && i < conf->raid_disks) - break; - p->bdev = NULL; - p->used_slot = 0; - err = 0; - break; + if (p->used_slot) { + if (p->operational) { + err = -EBUSY; + goto abort; } + p->bdev = NULL; + p->used_slot = 0; + err = 0; } if (err) MD_BUG(); diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h index a59767eb6de7..214a9163269a 100644 --- a/include/linux/raid/md_k.h +++ b/include/linux/raid/md_k.h @@ -207,9 +207,9 @@ struct mdk_personality_s int (*error_handler)(mddev_t *mddev, struct block_device *bdev); int (*hot_add_disk) (mddev_t *mddev, mdp_disk_t *descriptor, mdk_rdev_t *rdev); int (*hot_remove_disk) (mddev_t *mddev, int number); - int (*spare_write) (mddev_t *mddev, int number); + int (*spare_write) (mddev_t *mddev); int (*spare_inactive) (mddev_t *mddev); - int (*spare_active) (mddev_t *mddev, mdp_disk_t **descriptor); + int (*spare_active) (mddev_t *mddev); int (*sync_request)(mddev_t *mddev, sector_t sector_nr, int go_faster); }; -- cgit v1.2.3 From 9347ddf5f84f95178c3bca58b5eef2f2afa75a63 Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Thu, 18 Jul 2002 19:09:21 -0700 Subject: [PATCH] MD - Add raid_disk field to rdev Add raid_disk field to rdev Also change find_rdev_nr to find based on position in array (raid_disk) not position in superblock (number). --- drivers/md/linear.c | 2 +- drivers/md/md.c | 8 ++++++-- drivers/md/raid1.c | 9 ++++++--- drivers/md/raid5.c | 9 ++++++--- include/linux/raid/md_k.h | 1 + 5 files changed, 20 insertions(+), 9 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/linear.c b/drivers/md/linear.c index 5e71165662eb..5487ce306d71 100644 --- a/drivers/md/linear.c +++ b/drivers/md/linear.c @@ -52,7 +52,7 @@ static int linear_run (mddev_t *mddev) conf->smallest = NULL; cnt = 0; ITERATE_RDEV(mddev,rdev,tmp) { - int j = rdev->sb->this_disk.raid_disk; + int j = rdev->raid_disk; dev_info_t *disk = conf->disks + j; if (j < 0 || j > mddev->sb->raid_disks || disk->bdev) { diff --git a/drivers/md/md.c b/drivers/md/md.c index 04d44dd199cf..dac5d26ef36c 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -242,7 +242,7 @@ mdk_rdev_t * find_rdev_nr(mddev_t *mddev, int nr) struct list_head *tmp; ITERATE_RDEV(mddev,rdev,tmp) { - if (rdev->desc_nr == nr) + if (rdev->raid_disk == nr) return rdev; } return NULL; @@ -1178,8 +1178,11 @@ static int analyze_sbs(mddev_t * mddev) if (sb->level == LEVEL_MULTIPATH) { rdev->alias_device = !!i; rdev->desc_nr = i++; - } else + rdev->raid_disk = rdev->desc_nr; + } else { rdev->desc_nr = rdev->sb->this_disk.number; + rdev->raid_disk = sb->disks[rdev->desc_nr].raid_disk; + } } /* * Fix up changed device names ... but only if this disk has a @@ -2106,6 +2109,7 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info) } rdev->old_dev = dev; rdev->desc_nr = info->number; + rdev->raid_disk = info->raid_disk; bind_rdev_to_array(rdev, mddev); diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 91238ae3c2bc..cdf94c0928e5 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -713,16 +713,19 @@ static int raid1_spare_active(mddev_t *mddev) /* * do the switch finally */ - spare_rdev = find_rdev_nr(mddev, spare_desc->number); - failed_rdev = find_rdev_nr(mddev, failed_desc->number); + spare_rdev = find_rdev_nr(mddev, spare_disk); + failed_rdev = find_rdev_nr(mddev, failed_disk); /* * There must be a spare_rdev, but there may not be a * failed_rdev. That slot might be empty... */ spare_rdev->desc_nr = failed_desc->number; - if (failed_rdev) + spare_rdev->raid_disk = failed_disk; + if (failed_rdev) { failed_rdev->desc_nr = spare_desc->number; + failed_rdev->raid_disk = spare_disk; + } xchg_values(*spare_desc, *failed_desc); xchg_values(*fdisk, *sdisk); diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index a4c9d407ddc1..966195f7e757 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -1739,15 +1739,18 @@ static int raid5_spare_active(mddev_t *mddev) /* * do the switch finally */ - spare_rdev = find_rdev_nr(mddev, spare_desc->number); - failed_rdev = find_rdev_nr(mddev, failed_desc->number); + spare_rdev = find_rdev_nr(mddev, spare_disk); + failed_rdev = find_rdev_nr(mddev, failed_disk); /* There must be a spare_rdev, but there may not be a * failed_rdev. That slot might be empty... */ spare_rdev->desc_nr = failed_desc->number; - if (failed_rdev) + spare_rdev->raid_disk = failed_disk; + if (failed_rdev) { failed_rdev->desc_nr = spare_desc->number; + failed_rdev->raid_disk = spare_disk; + } xchg_values(*spare_desc, *failed_desc); xchg_values(*fdisk, *sdisk); diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h index 214a9163269a..18f89adb4b0c 100644 --- a/include/linux/raid/md_k.h +++ b/include/linux/raid/md_k.h @@ -159,6 +159,7 @@ struct mdk_rdev_s int alias_device; /* device alias to the same disk */ int faulty; /* if faulty do not issue IO requests */ int desc_nr; /* descriptor index in the superblock */ + int raid_disk; /* role of device in array */ }; typedef struct mdk_personality_s mdk_personality_t; -- cgit v1.2.3 From 8ee831455426e47e8e3b98e7683c594d551c84d6 Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Thu, 18 Jul 2002 19:09:33 -0700 Subject: [PATCH] MD - Add in_sync flag to each rdev Add in_sync flag to each rdev This currently mirrors the MD_DISK_SYNC superblock flag, but soon it will be authoritative and the superblock will only be consulted at start time. --- drivers/md/md.c | 19 ++++++++++++++++++- drivers/md/raid1.c | 1 + drivers/md/raid5.c | 1 + include/linux/raid/md_k.h | 2 ++ 4 files changed, 22 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/md/md.c b/drivers/md/md.c index dac5d26ef36c..64dd07bf36a0 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -1179,9 +1179,19 @@ static int analyze_sbs(mddev_t * mddev) rdev->alias_device = !!i; rdev->desc_nr = i++; rdev->raid_disk = rdev->desc_nr; + rdev->in_sync = 1; } else { + mdp_disk_t *desc; rdev->desc_nr = rdev->sb->this_disk.number; - rdev->raid_disk = sb->disks[rdev->desc_nr].raid_disk; + desc = sb->disks + rdev->desc_nr; + rdev->raid_disk = desc->raid_disk; + rdev->in_sync = rdev->faulty = 0; + + if (desc->state & (1<faulty = 1; + else if (desc->state & (1<raid_disk < mddev->sb-raid_disks) + rdev->in_sync = 1; } } /* @@ -2110,6 +2120,11 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info) rdev->old_dev = dev; rdev->desc_nr = info->number; rdev->raid_disk = info->raid_disk; + rdev->faulty = 0; + if (rdev->raid_disk < mddev->sb->raid_disks) + rdev->in_sync = (info->state & (1<in_sync = 0; bind_rdev_to_array(rdev, mddev); @@ -2271,6 +2286,7 @@ static int hot_add_disk(mddev_t * mddev, kdev_t dev) err = -EINVAL; goto abort_export; } + rdev->in_sync = 0; bind_rdev_to_array(rdev, mddev); /* @@ -2852,6 +2868,7 @@ int md_error(mddev_t *mddev, struct block_device *bdev) if (!mddev->pers->error_handler || mddev->pers->error_handler(mddev,bdev) <= 0) { rrdev->faulty = 1; + rrdev->in_sync = 0; } else return 1; /* diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index cdf94c0928e5..971a30c9ed0b 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -726,6 +726,7 @@ static int raid1_spare_active(mddev_t *mddev) failed_rdev->desc_nr = spare_desc->number; failed_rdev->raid_disk = spare_disk; } + spare_rdev->in_sync = 1; xchg_values(*spare_desc, *failed_desc); xchg_values(*fdisk, *sdisk); diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 966195f7e757..09e4735e3a9f 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -1751,6 +1751,7 @@ static int raid5_spare_active(mddev_t *mddev) failed_rdev->desc_nr = spare_desc->number; failed_rdev->raid_disk = spare_disk; } + spare_rdev->in_sync = 1; xchg_values(*spare_desc, *failed_desc); xchg_values(*fdisk, *sdisk); diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h index 18f89adb4b0c..f3c8dcc7d8a8 100644 --- a/include/linux/raid/md_k.h +++ b/include/linux/raid/md_k.h @@ -158,6 +158,8 @@ struct mdk_rdev_s int alias_device; /* device alias to the same disk */ int faulty; /* if faulty do not issue IO requests */ + int in_sync; /* device is a full member of the array */ + int desc_nr; /* descriptor index in the superblock */ int raid_disk; /* role of device in array */ }; -- cgit v1.2.3 From d58aa811a0d3ce0ad83cd2b70909e0ac47479e67 Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Thu, 18 Jul 2002 19:09:48 -0700 Subject: [PATCH] MD - Add "degraded" field to md device Add "degraded" field to md device This is used to determine if a spare should be added without relying on the superblock. --- drivers/md/md.c | 2 +- drivers/md/raid1.c | 8 +++++++- drivers/md/raid5.c | 8 +++++--- include/linux/raid/md_k.h | 4 ++++ 4 files changed, 17 insertions(+), 5 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/md.c b/drivers/md/md.c index 64dd07bf36a0..98544cd02a8b 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -3354,7 +3354,7 @@ void md_do_recovery(void *data) wake_up(&resync_wait); } - if (sb->active_disks < sb->raid_disks) { + if (mddev->degraded) { mddev->spare = get_spare(mddev); if (!mddev->spare) printk(KERN_ERR "md%d: no spare disk to reconstruct array! " diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 971a30c9ed0b..e684d856efd2 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -581,8 +581,10 @@ static void mark_disk_bad(mddev_t *mddev, int failed) mark_disk_faulty(sb->disks+mirror->number); mark_disk_nonsync(sb->disks+mirror->number); mark_disk_inactive(sb->disks+mirror->number); - if (!mirror->write_only) + if (!mirror->write_only) { sb->active_disks--; + mddev->degraded++; + } sb->working_disks--; sb->failed_disks++; mddev->sb_dirty = 1; @@ -758,6 +760,7 @@ static int raid1_spare_active(mddev_t *mddev) */ conf->working_disks++; + mddev->degraded--; abort: spin_unlock_irq(&conf->device_lock); @@ -1338,6 +1341,7 @@ static int run(mddev_t *mddev) goto out_free_conf; } + mddev->degraded = 0; for (i = 0; i < MD_SB_DISKS; i++) { descriptor = sb->disks+i; @@ -1355,6 +1359,8 @@ static int run(mddev_t *mddev) disk->used_slot = 1; disk->head_position = 0; } + if (!disk->used_slot && disk_idk < conf->raid_disks) + mddev->degraded++; } /* diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 09e4735e3a9f..029aa430bfce 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -460,6 +460,7 @@ static int error(mddev_t *mddev, struct block_device *bdev) sb->working_disks--; sb->failed_disks++; mddev->sb_dirty = 1; + mddev->degraded++; conf->working_disks--; conf->failed_disks++; printk (KERN_ALERT @@ -1500,7 +1501,7 @@ static int run (mddev_t *mddev) /* * 0 for a fully functional array, 1 for a degraded array. */ - conf->failed_disks = conf->raid_disks - conf->working_disks; + mddev->degraded = conf->failed_disks = conf->raid_disks - conf->working_disks; conf->mddev = mddev; conf->chunk_size = sb->chunk_size; conf->level = sb->level; @@ -1523,12 +1524,12 @@ static int run (mddev_t *mddev) printk(KERN_ERR "raid5: unsupported parity algorithm %d for md%d\n", conf->algorithm, mdidx(mddev)); goto abort; } - if (conf->failed_disks > 1) { + if (mddev->degraded > 1) { printk(KERN_ERR "raid5: not enough operational devices for md%d (%d/%d failed)\n", mdidx(mddev), conf->failed_disks, conf->raid_disks); goto abort; } - if (conf->failed_disks == 1 && + if (mddev->degraded == 1 && !(sb->state & (1<degraded--; conf->failed_disks--; conf->working_disks++; conf->spare = NULL; diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h index f3c8dcc7d8a8..369a2e56d22c 100644 --- a/include/linux/raid/md_k.h +++ b/include/linux/raid/md_k.h @@ -192,6 +192,10 @@ struct mddev_s atomic_t active; mdp_disk_t *spare; + int degraded; /* whether md should consider + * adding a spare + */ + atomic_t recovery_active; /* blocks scheduled, but not written */ wait_queue_head_t recovery_wait; -- cgit v1.2.3 From d109d34c22563d8d26e319c731999abd1ca4fe97 Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Thu, 18 Jul 2002 19:10:16 -0700 Subject: [PATCH] MD - Don't maintain disc status in superblock. Don't maintain disc status in superblock. The state is now in rdev so we don't maintain it in superblock any more. We also nolonger test content of superblock for disk status mddev->spare is now an rdev and not a superblock fragment. --- drivers/md/md.c | 387 +++++++--------------------------------------- drivers/md/multipath.c | 69 ++------- drivers/md/raid1.c | 128 ++++----------- drivers/md/raid5.c | 124 ++++----------- include/linux/raid/md_k.h | 6 +- 5 files changed, 137 insertions(+), 577 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/md.c b/drivers/md/md.c index aeea2b334eaa..e317eba13539 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -342,23 +342,6 @@ static unsigned int zoned_raid_size(mddev_t *mddev) return 0; } -static void remove_descriptor(mdp_disk_t *disk, mdp_super_t *sb) -{ - if (disk_active(disk)) { - sb->working_disks--; - } else { - if (disk_spare(disk)) { - sb->spare_disks--; - sb->working_disks--; - } else { - sb->failed_disks--; - } - } - sb->nr_disks--; - disk->major = 0; - disk->minor = 0; - mark_disk_removed(disk); -} #define BAD_MAGIC KERN_ERR \ "md: invalid raid superblock magic on %s\n" @@ -1091,8 +1074,8 @@ abort_free: static int analyze_sbs(mddev_t * mddev) { int out_of_date = 0, i; - struct list_head *tmp, *tmp2; - mdk_rdev_t *rdev, *rdev2, *freshest; + struct list_head *tmp; + mdk_rdev_t *rdev, *freshest; mdp_super_t *sb; /* @@ -1216,203 +1199,15 @@ static int analyze_sbs(mddev_t * mddev) rdev->raid_disk = desc->raid_disk; rdev->in_sync = rdev->faulty = 0; - if (desc->state & (1<state & (1<faulty = 1; - else if (desc->state & (1<raid_disk < mddev->sb-raid_disks) - rdev->in_sync = 1; - } - } - /* - * Fix up changed device names ... but only if this disk has a - * recent update time. Use faulty checksum ones too. - */ - if (mddev->sb->level != LEVEL_MULTIPATH) - ITERATE_RDEV(mddev,rdev,tmp) { - __u64 ev1, ev2, ev3; - if (rdev->faulty || rdev->alias_device) { - MD_BUG(); - goto abort; - } - ev1 = md_event(rdev->sb); - ev2 = md_event(sb); - ev3 = ev2; - --ev3; - if (!kdev_same(rdev->dev, rdev->old_dev) && - ((ev1 == ev2) || (ev1 == ev3))) { - mdp_disk_t *desc; - - printk(KERN_WARNING "md: device name has changed from %s to %s since last import!\n", - partition_name(rdev->old_dev), partition_name(rdev->dev)); - if (rdev->desc_nr == -1) { - MD_BUG(); - goto abort; - } - desc = &sb->disks[rdev->desc_nr]; - if (!kdev_same( rdev->old_dev, mk_kdev(desc->major, desc->minor))) { - MD_BUG(); - goto abort; - } - desc->major = major(rdev->dev); - desc->minor = minor(rdev->dev); - desc = &rdev->sb->this_disk; - desc->major = major(rdev->dev); - desc->minor = minor(rdev->dev); - } - } - - /* - * Remove unavailable and faulty devices ... - * - * note that if an array becomes completely unrunnable due to - * missing devices, we do not write the superblock back, so the - * administrator has a chance to fix things up. The removal thus - * only happens if it's nonfatal to the contents of the array. - */ - for (i = 0; i < MD_SB_DISKS; i++) { - int found; - mdp_disk_t *desc; - kdev_t dev; - - desc = sb->disks + i; - dev = mk_kdev(desc->major, desc->minor); - - /* - * We kick faulty devices/descriptors immediately. - * - * Note: multipath devices are a special case. Since we - * were able to read the superblock on the path, we don't - * care if it was previously marked as faulty, it's up now - * so enable it. - */ - if (disk_faulty(desc) && mddev->sb->level != LEVEL_MULTIPATH) { - found = 0; - ITERATE_RDEV(mddev,rdev,tmp) { - if (rdev->desc_nr != desc->number) - continue; - printk(KERN_WARNING "md%d: kicking faulty %s!\n", - mdidx(mddev),partition_name(rdev->dev)); kick_rdev_from_array(rdev); - found = 1; - break; - } - if (!found) { - if (kdev_none(dev)) - continue; - printk(KERN_WARNING "md%d: removing former faulty %s!\n", - mdidx(mddev), partition_name(dev)); - } - remove_descriptor(desc, sb); - continue; - } else if (disk_faulty(desc)) { - /* - * multipath entry marked as faulty, unfaulty it - */ - rdev = find_rdev(mddev, dev); - if(rdev) - mark_disk_spare(desc); - else - remove_descriptor(desc, sb); - } - - if (kdev_none(dev)) - continue; - /* - * Is this device present in the rdev ring? - */ - found = 0; - ITERATE_RDEV(mddev,rdev,tmp) { - /* - * Multi-path IO special-case: since we have no - * this_disk descriptor at auto-detect time, - * we cannot check rdev->number. - * We can check the device though. - */ - if ((sb->level == LEVEL_MULTIPATH) && - kdev_same(rdev->dev, - mk_kdev(desc->major,desc->minor))) { - found = 1; - break; - } - if (rdev->desc_nr == desc->number) { - found = 1; - break; - } + } else if (desc->state & (1<raid_disk < mddev->sb->raid_disks) + rdev->in_sync = 1; } - if (found) - continue; - - printk(KERN_WARNING "md%d: former device %s is unavailable, removing from array!\n", - mdidx(mddev), partition_name(dev)); - remove_descriptor(desc, sb); } - /* - * Double check wether all devices mentioned in the - * superblock are in the rdev ring. - */ - for (i = 0; i < MD_SB_DISKS; i++) { - mdp_disk_t *desc; - kdev_t dev; - - desc = sb->disks + i; - dev = mk_kdev(desc->major, desc->minor); - - if (kdev_none(dev)) - continue; - - if (disk_faulty(desc)) { - MD_BUG(); - goto abort; - } - - rdev = find_rdev(mddev, dev); - if (!rdev) { - MD_BUG(); - goto abort; - } - } - - /* - * Kick all rdevs that are not in the - * descriptor array: - */ - ITERATE_RDEV(mddev,rdev,tmp) { - if (rdev->desc_nr == -1) - kick_rdev_from_array(rdev); - } - - /* - * Do a final reality check. - */ - if (mddev->sb->level != LEVEL_MULTIPATH) { - ITERATE_RDEV(mddev,rdev,tmp) { - if (rdev->desc_nr == -1) { - MD_BUG(); - goto abort; - } - /* - * is the desc_nr unique? - */ - ITERATE_RDEV(mddev,rdev2,tmp2) { - if ((rdev2 != rdev) && - (rdev2->desc_nr == rdev->desc_nr)) { - MD_BUG(); - goto abort; - } - } - /* - * is the device unique? - */ - ITERATE_RDEV(mddev,rdev2,tmp2) { - if (rdev2 != rdev && - kdev_same(rdev2->dev, rdev->dev)) { - MD_BUG(); - goto abort; - } - } - } - } /* * Check if we can support this RAID array @@ -2029,11 +1824,27 @@ static int get_version(void * arg) static int get_array_info(mddev_t * mddev, void * arg) { mdu_array_info_t info; + int nr,working,active,failed,spare; + mdk_rdev_t *rdev; + struct list_head *tmp; if (!mddev->sb) { MD_BUG(); return -EINVAL; } + nr=working=active=failed=spare=0; + ITERATE_RDEV(mddev,rdev,tmp) { + nr++; + if (rdev->faulty) + failed++; + else { + working++; + if (rdev->in_sync) + active++; + else + spare++; + } + } SET_FROM_SB(major_version); SET_FROM_SB(minor_version); @@ -2048,10 +1859,10 @@ static int get_array_info(mddev_t * mddev, void * arg) SET_FROM_SB(utime); SET_FROM_SB(state); - SET_FROM_SB(active_disks); - SET_FROM_SB(working_disks); - SET_FROM_SB(failed_disks); - SET_FROM_SB(spare_disks); + info.active_disks = active; + info.working_disks = working; + info.failed_disks = failed; + info.spare_disks = spare; SET_FROM_SB(layout); SET_FROM_SB(chunk_size); @@ -2063,11 +1874,12 @@ static int get_array_info(mddev_t * mddev, void * arg) } #undef SET_FROM_SB -#define SET_FROM_SB(x) info.x = mddev->sb->disks[nr].x + static int get_disk_info(mddev_t * mddev, void * arg) { mdu_disk_info_t info; unsigned int nr; + mdk_rdev_t *rdev; if (!mddev->sb) return -EINVAL; @@ -2079,25 +1891,34 @@ static int get_disk_info(mddev_t * mddev, void * arg) if (nr >= MD_SB_DISKS) return -EINVAL; - SET_FROM_SB(major); - SET_FROM_SB(minor); - SET_FROM_SB(raid_disk); - SET_FROM_SB(state); + rdev = find_rdev_nr(mddev, nr); + if (rdev) { + info.major = major(rdev->dev); + info.minor = minor(rdev->dev); + info.raid_disk = rdev->raid_disk; + info.state = 0; + if (rdev->faulty) + info.state |= (1<in_sync) { + info.state |= (1<sb->disks[nr].x = info->x static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info) { int size, persistent; mdk_rdev_t *rdev; - unsigned int nr; kdev_t dev; dev = mk_kdev(info->major,info->minor); if (!mddev->sb) { @@ -2127,19 +1948,6 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info) return 0; } - nr = info->number; - if (nr >= mddev->sb->nr_disks) { - MD_BUG(); - return -EINVAL; - } - - - SET_SB(number); - SET_SB(major); - SET_SB(minor); - SET_SB(raid_disk); - SET_SB(state); - if (!(info->state & (1<sb->size = size; } - /* - * sync all other superblocks with the main superblock - */ - sync_sbs(mddev); - return 0; } -#undef SET_SB static int hot_generate_error(mddev_t * mddev, kdev_t dev) { struct request_queue *q; mdk_rdev_t *rdev; - mdp_disk_t *disk; if (!mddev->pers) return -ENODEV; @@ -2199,8 +2000,7 @@ static int hot_generate_error(mddev_t * mddev, kdev_t dev) MD_BUG(); return -EINVAL; } - disk = &mddev->sb->disks[rdev->desc_nr]; - if (!disk_active(disk)) + if (!rdev->in_sync) return -ENODEV; q = bdev_get_queue(rdev->bdev); @@ -2218,7 +2018,6 @@ static int hot_remove_disk(mddev_t * mddev, kdev_t dev) { int err; mdk_rdev_t *rdev; - mdp_disk_t *disk; if (!mddev->pers) return -ENODEV; @@ -2236,21 +2035,10 @@ static int hot_remove_disk(mddev_t * mddev, kdev_t dev) if (!rdev) return -ENXIO; - if (rdev->desc_nr == -1) { - MD_BUG(); - return -EINVAL; - } - disk = &mddev->sb->disks[rdev->desc_nr]; - if (disk_active(disk)) { - MD_BUG(); + if (rdev->in_sync && ! rdev->faulty) goto busy; - } - if (disk_removed(disk)) { - MD_BUG(); - return -EINVAL; - } - err = mddev->pers->hot_remove_disk(mddev, disk->raid_disk); + err = mddev->pers->hot_remove_disk(mddev, rdev->raid_disk); if (err == -EBUSY) { MD_BUG(); goto busy; @@ -2260,7 +2048,6 @@ static int hot_remove_disk(mddev_t * mddev, kdev_t dev) return -EINVAL; } - remove_descriptor(disk, mddev->sb); kick_rdev_from_array(rdev); md_update_sb(mddev); @@ -2276,7 +2063,6 @@ static int hot_add_disk(mddev_t * mddev, kdev_t dev) int i, err, persistent; unsigned int size; mdk_rdev_t *rdev; - mdp_disk_t *disk; if (!mddev->pers) return -ENODEV; @@ -2290,10 +2076,6 @@ static int hot_add_disk(mddev_t * mddev, kdev_t dev) return -EINVAL; } - rdev = find_rdev(mddev, dev); - if (rdev) - return -EBUSY; - rdev = md_import_device (dev, 0); if (IS_ERR(rdev)) { printk(KERN_WARNING "md: error, md_import_device() returned %ld\n", PTR_ERR(rdev)); @@ -2326,15 +2108,10 @@ static int hot_add_disk(mddev_t * mddev, kdev_t dev) rdev->size = size; rdev->sb_offset = calc_dev_sboffset(rdev, mddev, persistent); - disk = mddev->sb->disks + mddev->sb->raid_disks; - for (i = mddev->sb->raid_disks; i < MD_SB_DISKS; i++) { - disk = mddev->sb->disks + i; - - if (!disk->major && !disk->minor) + for (i = mddev->sb->raid_disks; i < MD_SB_DISKS; i++) + if (find_rdev_nr(mddev,i)==NULL) break; - if (disk_removed(disk)) - break; - } + if (i == MD_SB_DISKS) { printk(KERN_WARNING "md%d: can not hot-add to full array!\n", mdidx(mddev)); @@ -2342,34 +2119,15 @@ static int hot_add_disk(mddev_t * mddev, kdev_t dev) goto abort_unbind_export; } - if (disk_removed(disk)) { - /* - * reuse slot - */ - if (disk->number != i) { - MD_BUG(); - err = -EINVAL; - goto abort_unbind_export; - } - } else { - disk->number = i; - } - - disk->raid_disk = disk->number; - disk->major = major(dev); - disk->minor = minor(dev); + rdev->desc_nr = i; + rdev->raid_disk = i; - if (mddev->pers->hot_add_disk(mddev, disk, rdev)) { + if (mddev->pers->hot_add_disk(mddev, rdev)) { MD_BUG(); err = -EINVAL; goto abort_unbind_export; } - mark_disk_spare(disk); - mddev->sb->nr_disks++; - mddev->sb->spare_disks++; - mddev->sb->working_disks++; - md_update_sb(mddev); /* @@ -2408,10 +2166,6 @@ static int set_array_info(mddev_t * mddev, mdu_array_info_t *info) SET_SB(not_persistent); SET_SB(state); - SET_SB(active_disks); - SET_SB(working_disks); - SET_SB(failed_disks); - SET_SB(spare_disks); SET_SB(layout); SET_SB(chunk_size); @@ -3076,28 +2830,18 @@ int unregister_md_personality(int pnum) return 0; } -mdp_disk_t *get_spare(mddev_t *mddev) +static mdk_rdev_t *get_spare(mddev_t *mddev) { - mdp_super_t *sb = mddev->sb; - mdp_disk_t *disk; mdk_rdev_t *rdev; struct list_head *tmp; ITERATE_RDEV(mddev,rdev,tmp) { if (rdev->faulty) continue; - if (!rdev->sb) { - MD_BUG(); - continue; - } - disk = &sb->disks[rdev->desc_nr]; - if (disk_faulty(disk)) { - MD_BUG(); + if (rdev->in_sync) continue; - } - if (disk_active(disk)) - continue; - return disk; + + return rdev; } return NULL; } @@ -3365,10 +3109,7 @@ void md_do_recovery(void *data) /* success...*/ if (mddev->spare) { mddev->pers->spare_active(mddev); - mark_disk_sync(mddev->spare); - mark_disk_active(mddev->spare); - sb->active_disks++; - sb->spare_disks--; + mddev->spare->in_sync = 1; mddev->spare = NULL; } } @@ -3390,7 +3131,7 @@ void md_do_recovery(void *data) "-- continuing in degraded mode\n", mdidx(mddev)); else printk(KERN_INFO "md%d: resyncing spare disk %s to replace failed disk\n", - mdidx(mddev), partition_name(mk_kdev(mddev->spare->major,mddev->spare->minor))); + mdidx(mddev), partition_name(mddev->spare->dev)); } if (!mddev->spare && mddev->in_sync) { /* nothing we can do ... */ @@ -3749,10 +3490,6 @@ void __init md_setup_drive(void) ainfo.not_persistent = 1; ainfo.state = (1 << MD_SB_CLEAN); - ainfo.active_disks = 0; - ainfo.working_disks = 0; - ainfo.failed_disks = 0; - ainfo.spare_disks = 0; ainfo.layout = 0; ainfo.chunk_size = md_setup_args.chunk[minor]; err = set_array_info(mddev, &ainfo); @@ -3765,10 +3502,7 @@ void __init md_setup_drive(void) dinfo.state = (1<sb->nr_disks++; mddev->sb->raid_disks++; - mddev->sb->active_disks++; - mddev->sb->working_disks++; err = add_new_disk (mddev, &dinfo); } } else { @@ -3883,5 +3617,4 @@ EXPORT_SYMBOL(md_wakeup_thread); EXPORT_SYMBOL(md_print_devices); EXPORT_SYMBOL(find_rdev_nr); EXPORT_SYMBOL(md_interrupt_thread); -EXPORT_SYMBOL(get_spare); MODULE_LICENSE("GPL"); diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index c201fda0189d..89c25ff4a857 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -214,15 +214,8 @@ static void mark_disk_bad (mddev_t *mddev, int failed) { multipath_conf_t *conf = mddev_to_conf(mddev); struct multipath_info *multipath = conf->multipaths+failed; - mdp_super_t *sb = mddev->sb; multipath->operational = 0; - mark_disk_faulty(sb->disks+multipath->number); - mark_disk_nonsync(sb->disks+multipath->number); - mark_disk_inactive(sb->disks+multipath->number); - sb->active_disks--; - sb->working_disks--; - sb->failed_disks++; mddev->sb_dirty = 1; conf->working_disks--; printk (DISK_FAILED, bdev_partition_name (multipath->bdev), @@ -296,30 +289,23 @@ static void print_multipath_conf (multipath_conf_t *conf) } -static int multipath_add_disk(mddev_t *mddev, mdp_disk_t *added_desc, - mdk_rdev_t *rdev) +static int multipath_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) { multipath_conf_t *conf = mddev->private; int err = 1; - int i; + struct multipath_info *p = conf->multipaths + rdev->raid_disk; print_multipath_conf(conf); spin_lock_irq(&conf->device_lock); - for (i = 0; i < MD_SB_DISKS; i++) { - struct multipath_info *p = conf->multipaths + i; - if (!p->used_slot) { - if (added_desc->number != i) - break; - p->number = added_desc->number; - p->raid_disk = added_desc->raid_disk; - p->bdev = rdev->bdev; - p->operational = 1; - p->used_slot = 1; - conf->nr_disks++; - conf->working_disks++; - err = 0; - break; - } + if (!p->used_slot) { + p->number = rdev->desc_nr; + p->raid_disk = rdev->raid_disk; + p->bdev = rdev->bdev; + p->operational = 1; + p->used_slot = 1; + conf->nr_disks++; + conf->working_disks++; + err = 0; } if (err) MD_BUG(); @@ -451,10 +437,9 @@ static void multipathd (void *data) static int multipath_run (mddev_t *mddev) { multipath_conf_t *conf; - int i, j, disk_idx; + int disk_idx; struct multipath_info *disk; mdp_super_t *sb = mddev->sb; - mdp_disk_t *desc; mdk_rdev_t *rdev; struct list_head *tmp; int num_rdevs = 0; @@ -498,32 +483,24 @@ static int multipath_run (mddev_t *mddev) continue; } - desc = &sb->disks[rdev->desc_nr]; - disk_idx = desc->raid_disk; + disk_idx = rdev->raid_disk; disk = conf->multipaths + disk_idx; - if (!disk_sync(desc)) - printk(NOT_IN_SYNC, bdev_partition_name(rdev->bdev)); - /* * Mark all disks as active to start with, there are no * spares. multipath_read_balance deals with choose * the "best" operational device. */ - disk->number = desc->number; - disk->raid_disk = desc->raid_disk; + disk->number = rdev->desc_nr; + disk->raid_disk = disk_idx; disk->bdev = rdev->bdev; disk->operational = 1; disk->used_slot = 1; - mark_disk_sync(desc); - mark_disk_active(desc); num_rdevs++; } - conf->raid_disks = sb->raid_disks = sb->active_disks = num_rdevs; - conf->nr_disks = sb->nr_disks = sb->working_disks = num_rdevs; - sb->failed_disks = 0; - sb->spare_disks = 0; + conf->raid_disks = sb->raid_disks = num_rdevs; + conf->nr_disks = num_rdevs; mddev->sb_dirty = 1; conf->mddev = mddev; conf->device_lock = SPIN_LOCK_UNLOCKED; @@ -551,18 +528,6 @@ static int multipath_run (mddev_t *mddev) } } - /* - * Regenerate the "device is in sync with the raid set" bit for - * each device. - */ - for (i = 0; i < MD_SB_DISKS; i++) { - mark_disk_nonsync(sb->disks+i); - for (j = 0; j < sb->raid_disks; j++) { - if (sb->disks[i].number == conf->multipaths[j].number) - mark_disk_sync(sb->disks+i); - } - } - printk(ARRAY_IS_ACTIVE, mdidx(mddev), sb->active_disks, sb->raid_disks, sb->spare_disks); /* diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index e684d856efd2..6dca5c9133e4 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -575,21 +575,13 @@ static void mark_disk_bad(mddev_t *mddev, int failed) { conf_t *conf = mddev_to_conf(mddev); mirror_info_t *mirror = conf->mirrors+failed; - mdp_super_t *sb = mddev->sb; mirror->operational = 0; - mark_disk_faulty(sb->disks+mirror->number); - mark_disk_nonsync(sb->disks+mirror->number); - mark_disk_inactive(sb->disks+mirror->number); if (!mirror->write_only) { - sb->active_disks--; mddev->degraded++; + conf->working_disks--; } - sb->working_disks--; - sb->failed_disks++; mddev->sb_dirty = 1; - if (!mirror->write_only) - conf->working_disks--; printk(DISK_FAILED, bdev_partition_name(mirror->bdev), conf->working_disks); } @@ -665,8 +657,6 @@ static int raid1_spare_active(mddev_t *mddev) int i, failed_disk = -1, spare_disk = -1; conf_t *conf = mddev->private; mirror_info_t *tmp, *sdisk, *fdisk; - mdp_super_t *sb = mddev->sb; - mdp_disk_t *failed_desc, *spare_desc; mdk_rdev_t *spare_rdev, *failed_rdev; print_conf(conf); @@ -701,17 +691,6 @@ static int raid1_spare_active(mddev_t *mddev) sdisk = conf->mirrors + spare_disk; fdisk = conf->mirrors + failed_disk; - spare_desc = &sb->disks[sdisk->number]; - failed_desc = &sb->disks[fdisk->number]; - - if (spare_desc->raid_disk != sdisk->raid_disk || - sdisk->raid_disk != spare_disk || fdisk->raid_disk != failed_disk || - failed_desc->raid_disk != fdisk->raid_disk) { - MD_BUG(); - err = 1; - goto abort; - } - /* * do the switch finally */ @@ -722,15 +701,13 @@ static int raid1_spare_active(mddev_t *mddev) * There must be a spare_rdev, but there may not be a * failed_rdev. That slot might be empty... */ - spare_rdev->desc_nr = failed_desc->number; + spare_rdev->desc_nr = failed_disk; spare_rdev->raid_disk = failed_disk; if (failed_rdev) { - failed_rdev->desc_nr = spare_desc->number; + failed_rdev->desc_nr = spare_disk; failed_rdev->raid_disk = spare_disk; } - spare_rdev->in_sync = 1; - xchg_values(*spare_desc, *failed_desc); xchg_values(*fdisk, *sdisk); /* @@ -740,9 +717,7 @@ static int raid1_spare_active(mddev_t *mddev) * give the proper raid_disk number to the now activated * disk. (this means we switch back these values) */ - xchg_values(spare_desc->raid_disk, failed_desc->raid_disk); xchg_values(sdisk->raid_disk, fdisk->raid_disk); - xchg_values(spare_desc->number, failed_desc->number); xchg_values(sdisk->number, fdisk->number); if (!sdisk->bdev) @@ -810,36 +785,26 @@ static int raid1_spare_write(mddev_t *mddev) return err; } -static int raid1_add_disk(mddev_t *mddev, mdp_disk_t *added_desc, - mdk_rdev_t *rdev) +static int raid1_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) { conf_t *conf = mddev->private; int err = 1; - int i; + mirror_info_t *p = conf->mirrors + rdev->raid_disk; print_conf(conf); spin_lock_irq(&conf->device_lock); - /* - * find the disk ... - */ - for (i = conf->raid_disks; i < MD_SB_DISKS; i++) { - mirror_info_t *p = conf->mirrors + i; - if (!p->used_slot) { - if (added_desc->number != i) - break; - p->number = added_desc->number; - p->raid_disk = added_desc->raid_disk; - /* it will be held open by rdev */ - p->bdev = rdev->bdev; - p->operational = 0; - p->write_only = 0; - p->spare = 1; - p->used_slot = 1; - p->head_position = 0; - conf->nr_disks++; - err = 0; - break; - } + if (!p->used_slot) { + p->number = rdev->desc_nr; + p->raid_disk = rdev->raid_disk; + /* it will be held open by rdev */ + p->bdev = rdev->bdev; + p->operational = 0; + p->write_only = 0; + p->spare = 1; + p->used_slot = 1; + p->head_position = 0; + conf->nr_disks++; + err = 0; } if (err) MD_BUG(); @@ -1222,7 +1187,6 @@ static int run(mddev_t *mddev) int i, j, disk_idx; mirror_info_t *disk; mdp_super_t *sb = mddev->sb; - mdp_disk_t *descriptor; mdk_rdev_t *rdev; struct list_head *tmp; @@ -1267,12 +1231,11 @@ static int run(mddev_t *mddev) MD_BUG(); continue; } - descriptor = &sb->disks[rdev->desc_nr]; - disk_idx = descriptor->raid_disk; + disk_idx = rdev->raid_disk; disk = conf->mirrors + disk_idx; - if (disk_faulty(descriptor)) { - disk->number = descriptor->number; + if (rdev->faulty) { + disk->number = rdev->desc_nr; disk->raid_disk = disk_idx; disk->bdev = rdev->bdev; disk->operational = 0; @@ -1282,19 +1245,7 @@ static int run(mddev_t *mddev) disk->head_position = 0; continue; } - if (disk_active(descriptor)) { - if (!disk_sync(descriptor)) { - printk(NOT_IN_SYNC, - bdev_partition_name(rdev->bdev)); - continue; - } - if ((descriptor->number > MD_SB_DISKS) || - (disk_idx > sb->raid_disks)) { - - printk(INCONSISTENT, - bdev_partition_name(rdev->bdev)); - continue; - } + if (rdev->in_sync) { if (disk->operational) { printk(ALREADY_RUNNING, bdev_partition_name(rdev->bdev), @@ -1303,7 +1254,7 @@ static int run(mddev_t *mddev) } printk(OPERATIONAL, bdev_partition_name(rdev->bdev), disk_idx); - disk->number = descriptor->number; + disk->number = rdev->desc_nr; disk->raid_disk = disk_idx; disk->bdev = rdev->bdev; disk->operational = 1; @@ -1317,7 +1268,7 @@ static int run(mddev_t *mddev) * Must be a spare disk .. */ printk(SPARE, bdev_partition_name(rdev->bdev)); - disk->number = descriptor->number; + disk->number = rdev->desc_nr; disk->raid_disk = disk_idx; disk->bdev = rdev->bdev; disk->operational = 0; @@ -1342,16 +1293,13 @@ static int run(mddev_t *mddev) } mddev->degraded = 0; - for (i = 0; i < MD_SB_DISKS; i++) { + for (i = 0; i < conf->raid_disks; i++) { - descriptor = sb->disks+i; - disk_idx = descriptor->raid_disk; - disk = conf->mirrors + disk_idx; + disk = conf->mirrors + i; - if (disk_faulty(descriptor) && (disk_idx < conf->raid_disks) && - !disk->used_slot) { - disk->number = descriptor->number; - disk->raid_disk = disk_idx; + if (!disk->used_slot) { + disk->number = i; + disk->raid_disk = i; disk->bdev = NULL; disk->operational = 0; disk->write_only = 0; @@ -1359,7 +1307,7 @@ static int run(mddev_t *mddev) disk->used_slot = 1; disk->head_position = 0; } - if (!disk->used_slot && disk_idk < conf->raid_disks) + if (!disk->used_slot) mddev->degraded++; } @@ -1383,23 +1331,7 @@ static int run(mddev_t *mddev) } } - - /* - * Regenerate the "device is in sync with the raid set" bit for - * each device. - */ - for (i = 0; i < MD_SB_DISKS; i++) { - mark_disk_nonsync(sb->disks+i); - for (j = 0; j < sb->raid_disks; j++) { - if (!conf->mirrors[j].operational) - continue; - if (sb->disks[i].number == conf->mirrors[j].number) - mark_disk_sync(sb->disks+i); - } - } - sb->active_disks = conf->working_disks; - - printk(ARRAY_IS_ACTIVE, mdidx(mddev), sb->active_disks, sb->raid_disks); + printk(ARRAY_IS_ACTIVE, mdidx(mddev), sb->raid_disks - mddev->degraded, sb->raid_disks); /* * Ok, everything is just fine now */ diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 029aa430bfce..95a4539d90d6 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -442,7 +442,6 @@ static void raid5_build_block (struct stripe_head *sh, int i) static int error(mddev_t *mddev, struct block_device *bdev) { raid5_conf_t *conf = (raid5_conf_t *) mddev->private; - mdp_super_t *sb = mddev->sb; struct disk_info *disk; int i; @@ -453,12 +452,6 @@ static int error(mddev_t *mddev, struct block_device *bdev) continue; if (disk->operational) { disk->operational = 0; - mark_disk_faulty(sb->disks+disk->number); - mark_disk_nonsync(sb->disks+disk->number); - mark_disk_inactive(sb->disks+disk->number); - sb->active_disks--; - sb->working_disks--; - sb->failed_disks++; mddev->sb_dirty = 1; mddev->degraded++; conf->working_disks--; @@ -486,12 +479,6 @@ static int error(mddev_t *mddev, struct block_device *bdev) disk->operational = 0; disk->write_only = 0; conf->spare = NULL; - mark_disk_faulty(sb->disks+disk->number); - mark_disk_nonsync(sb->disks+disk->number); - mark_disk_inactive(sb->disks+disk->number); - sb->spare_disks--; - sb->working_disks--; - sb->failed_disks++; mddev->sb_dirty = 1; @@ -1376,9 +1363,8 @@ static void raid5d (void *data) static int run (mddev_t *mddev) { raid5_conf_t *conf; - int i, j, raid_disk, memory; + int i, raid_disk, memory; mdp_super_t *sb = mddev->sb; - mdp_disk_t *desc; mdk_rdev_t *rdev; struct disk_info *disk; struct list_head *tmp; @@ -1419,17 +1405,12 @@ static int run (mddev_t *mddev) * the disk only to get a pointer to the descriptor on * the main superblock, which might be more recent. */ - desc = sb->disks + rdev->desc_nr; - raid_disk = desc->raid_disk; + raid_disk = rdev->raid_disk; disk = conf->disks + raid_disk; - if (disk_faulty(desc)) { + if (rdev->faulty) { printk(KERN_ERR "raid5: disabled device %s (errors detected)\n", bdev_partition_name(rdev->bdev)); - if (!rdev->faulty) { - MD_BUG(); - goto abort; - } - disk->number = desc->number; + disk->number = rdev->desc_nr; disk->raid_disk = raid_disk; disk->bdev = rdev->bdev; @@ -1439,23 +1420,14 @@ static int run (mddev_t *mddev) disk->used_slot = 1; continue; } - if (disk_active(desc)) { - if (!disk_sync(desc)) { - printk(KERN_ERR "raid5: disabled device %s (not in sync)\n", bdev_partition_name(rdev->bdev)); - MD_BUG(); - goto abort; - } - if (raid_disk > sb->raid_disks) { - printk(KERN_ERR "raid5: disabled device %s (inconsistent descriptor)\n", bdev_partition_name(rdev->bdev)); - continue; - } + if (rdev->in_sync) { if (disk->operational) { printk(KERN_ERR "raid5: disabled device %s (device %d already operational)\n", bdev_partition_name(rdev->bdev), raid_disk); continue; } printk(KERN_INFO "raid5: device %s operational as raid disk %d\n", bdev_partition_name(rdev->bdev), raid_disk); - disk->number = desc->number; + disk->number = rdev->desc_nr; disk->raid_disk = raid_disk; disk->bdev = rdev->bdev; disk->operational = 1; @@ -1467,7 +1439,7 @@ static int run (mddev_t *mddev) * Must be a spare disk .. */ printk(KERN_INFO "raid5: spare disk %s\n", bdev_partition_name(rdev->bdev)); - disk->number = desc->number; + disk->number = rdev->desc_nr; disk->raid_disk = raid_disk; disk->bdev = rdev->bdev; @@ -1478,16 +1450,13 @@ static int run (mddev_t *mddev) } } - for (i = 0; i < MD_SB_DISKS; i++) { - desc = sb->disks + i; - raid_disk = desc->raid_disk; - disk = conf->disks + raid_disk; + for (i = 0; i < sb->raid_disks; i++) { + disk = conf->disks + i; - if (disk_faulty(desc) && (raid_disk < sb->raid_disks) && - !conf->disks[raid_disk].used_slot) { + if (!disk->used_slot) { - disk->number = desc->number; - disk->raid_disk = raid_disk; + disk->number = i; + disk->raid_disk = i; disk->bdev = NULL; disk->operational = 0; @@ -1555,22 +1524,7 @@ static int run (mddev_t *mddev) } else printk(KERN_INFO "raid5: allocated %dkB for md%d\n", memory, mdidx(mddev)); - /* - * Regenerate the "device is in sync with the raid set" bit for - * each device. - */ - for (i = 0; i < MD_SB_DISKS ; i++) { - mark_disk_nonsync(sb->disks + i); - for (j = 0; j < sb->raid_disks; j++) { - if (!conf->disks[j].operational) - continue; - if (sb->disks[i].number == conf->disks[j].number) - mark_disk_sync(sb->disks + i); - } - } - sb->active_disks = conf->working_disks; - - if (sb->active_disks == sb->raid_disks) + if (conf->working_disks == conf->raid_disks) printk("raid5: raid level %d set md%d active with %d out of %d devices, algorithm %d\n", conf->level, mdidx(mddev), sb->active_disks, sb->raid_disks, conf->algorithm); else printk(KERN_ALERT "raid5: raid level %d set md%d active with %d out of %d devices, algorithm %d\n", conf->level, mdidx(mddev), sb->active_disks, sb->raid_disks, conf->algorithm); @@ -1693,8 +1647,6 @@ static int raid5_spare_active(mddev_t *mddev) int i, failed_disk=-1, spare_disk=-1; raid5_conf_t *conf = mddev->private; struct disk_info *tmp, *sdisk, *fdisk; - mdp_super_t *sb = mddev->sb; - mdp_disk_t *failed_desc, *spare_desc; mdk_rdev_t *spare_rdev, *failed_rdev; print_raid5_conf(conf); @@ -1726,17 +1678,6 @@ static int raid5_spare_active(mddev_t *mddev) sdisk = conf->disks + spare_disk; fdisk = conf->disks + failed_disk; - spare_desc = &sb->disks[sdisk->number]; - failed_desc = &sb->disks[fdisk->number]; - - if ( spare_desc->raid_disk != sdisk->raid_disk || - sdisk->raid_disk != spare_disk || fdisk->raid_disk != failed_disk || - failed_desc->raid_disk != fdisk->raid_disk) { - MD_BUG(); - err = 1; - goto abort; - } - /* * do the switch finally */ @@ -1746,15 +1687,13 @@ static int raid5_spare_active(mddev_t *mddev) /* There must be a spare_rdev, but there may not be a * failed_rdev. That slot might be empty... */ - spare_rdev->desc_nr = failed_desc->number; + spare_rdev->desc_nr = failed_disk; spare_rdev->raid_disk = failed_disk; if (failed_rdev) { - failed_rdev->desc_nr = spare_desc->number; + failed_rdev->desc_nr = spare_disk; failed_rdev->raid_disk = spare_disk; } - spare_rdev->in_sync = 1; - xchg_values(*spare_desc, *failed_desc); xchg_values(*fdisk, *sdisk); /* @@ -1765,9 +1704,7 @@ static int raid5_spare_active(mddev_t *mddev) * disk. (this means we switch back these values) */ - xchg_values(spare_desc->raid_disk, failed_desc->raid_disk); xchg_values(sdisk->raid_disk, fdisk->raid_disk); - xchg_values(spare_desc->number, failed_desc->number); xchg_values(sdisk->number, fdisk->number); if (!sdisk->bdev) @@ -1865,12 +1802,11 @@ abort: return err; } -static int raid5_add_disk(mddev_t *mddev, mdp_disk_t *added_desc, - mdk_rdev_t *rdev) +static int raid5_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) { raid5_conf_t *conf = mddev->private; int err = 1; - int i; + struct disk_info *p = conf->disks + rdev->raid_disk; print_raid5_conf(conf); spin_lock_irq(&conf->device_lock); @@ -1878,22 +1814,16 @@ static int raid5_add_disk(mddev_t *mddev, mdp_disk_t *added_desc, * find the disk ... */ - for (i = conf->raid_disks; i < MD_SB_DISKS; i++) { - struct disk_info *p = conf->disks + i; - if (!p->used_slot) { - if (added_desc->number != i) - break; - p->number = added_desc->number; - p->raid_disk = added_desc->raid_disk; - /* it will be held open by rdev */ - p->bdev = rdev->bdev; - p->operational = 0; - p->write_only = 0; - p->spare = 1; - p->used_slot = 1; - err = 0; - break; - } + if (!p->used_slot) { + p->number = rdev->desc_nr; + p->raid_disk = rdev->raid_disk; + /* it will be held open by rdev */ + p->bdev = rdev->bdev; + p->operational = 0; + p->write_only = 0; + p->spare = 1; + p->used_slot = 1; + err = 0; } if (err) MD_BUG(); diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h index 369a2e56d22c..cf99f1d018fe 100644 --- a/include/linux/raid/md_k.h +++ b/include/linux/raid/md_k.h @@ -190,7 +190,7 @@ struct mddev_s int in_sync; /* know to not need resync */ struct semaphore reconfig_sem; atomic_t active; - mdp_disk_t *spare; + mdk_rdev_t *spare; int degraded; /* whether md should consider * adding a spare @@ -212,7 +212,7 @@ struct mdk_personality_s int (*stop)(mddev_t *mddev); int (*status)(char *page, mddev_t *mddev); int (*error_handler)(mddev_t *mddev, struct block_device *bdev); - int (*hot_add_disk) (mddev_t *mddev, mdp_disk_t *descriptor, mdk_rdev_t *rdev); + int (*hot_add_disk) (mddev_t *mddev, mdk_rdev_t *rdev); int (*hot_remove_disk) (mddev_t *mddev, int number); int (*spare_write) (mddev_t *mddev); int (*spare_inactive) (mddev_t *mddev); @@ -238,7 +238,7 @@ static inline kdev_t mddev_to_kdev(mddev_t * mddev) extern mdk_rdev_t * find_rdev(mddev_t * mddev, kdev_t dev); extern mdk_rdev_t * find_rdev_nr(mddev_t *mddev, int nr); -extern mdp_disk_t *get_spare(mddev_t *mddev); +extern mdk_rdev_t *get_spare(mddev_t *mddev); /* * iterates through some rdev ringlist. It's safe to remove the -- cgit v1.2.3 From f2421da3b3bb340eba48d1815affed5984f23ff0 Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Thu, 18 Jul 2002 19:10:30 -0700 Subject: [PATCH] MD - Remove old_dev field. Remove old_dev field. We used to monitor the pervious device number of a component device for superblock maintenance. This is not needed any more. --- drivers/md/md.c | 12 ++---------- include/linux/raid/md_k.h | 1 - 2 files changed, 2 insertions(+), 11 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/md.c b/drivers/md/md.c index e317eba13539..cf0bba0726cf 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -708,8 +708,8 @@ static void print_sb(mdp_super_t *sb) static void print_rdev(mdk_rdev_t *rdev) { - printk(KERN_INFO "md: rdev %s: O:%s, SZ:%08ld F:%d DN:%d ", - partition_name(rdev->dev), partition_name(rdev->old_dev), + printk(KERN_INFO "md: rdev %s, SZ:%08ld F:%d DN:%d ", + partition_name(rdev->dev), rdev->size, rdev->faulty, rdev->desc_nr); if (rdev->sb) { printk(KERN_INFO "md: rdev superblock:\n"); @@ -1029,12 +1029,6 @@ static mdk_rdev_t *md_import_device(kdev_t newdev, int on_disk) partition_name(newdev)); goto abort_free; } - - if (rdev->sb->level != LEVEL_MULTIPATH) - rdev->old_dev = mk_kdev(rdev->sb->this_disk.major, - rdev->sb->this_disk.minor); - else - rdev->old_dev = NODEV; } INIT_LIST_HEAD(&rdev->same_set); @@ -1954,7 +1948,6 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info) printk(KERN_WARNING "md: error, md_import_device() returned %ld\n", PTR_ERR(rdev)); return PTR_ERR(rdev); } - rdev->old_dev = dev; rdev->desc_nr = info->number; rdev->raid_disk = info->raid_disk; rdev->faulty = 0; @@ -2104,7 +2097,6 @@ static int hot_add_disk(mddev_t * mddev, kdev_t dev) * The rest should better be atomic, we can have disk failures * noticed in interrupt contexts ... */ - rdev->old_dev = dev; rdev->size = size; rdev->sb_offset = calc_dev_sboffset(rdev, mddev, persistent); diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h index cf99f1d018fe..6b6845e8fd82 100644 --- a/include/linux/raid/md_k.h +++ b/include/linux/raid/md_k.h @@ -145,7 +145,6 @@ struct mdk_rdev_s struct list_head same_set; /* RAID devices within the same set */ kdev_t dev; /* Device number */ - kdev_t old_dev; /* "" when it was last imported */ unsigned long size; /* Device size (in blocks) */ mddev_t *mddev; /* RAID array if running */ unsigned long last_events; /* IO event timestamp */ -- cgit v1.2.3 From 4395b447666e5aabcee8e1b695389aab712526c3 Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Thu, 18 Jul 2002 19:10:44 -0700 Subject: [PATCH] MD - nr_disks is gone from multipath/raid1 nr_disks is gone from multipath/raid1 Never used. --- drivers/md/multipath.c | 7 ++----- drivers/md/raid1.c | 7 ++----- include/linux/raid/multipath.h | 1 - include/linux/raid/raid1.h | 1 - 4 files changed, 4 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index 89c25ff4a857..94c37a85ca9a 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -274,8 +274,8 @@ static void print_multipath_conf (multipath_conf_t *conf) printk("(conf==NULL)\n"); return; } - printk(" --- wd:%d rd:%d nd:%d\n", conf->working_disks, - conf->raid_disks, conf->nr_disks); + printk(" --- wd:%d rd:%d\n", conf->working_disks, + conf->raid_disks); for (i = 0; i < MD_SB_DISKS; i++) { tmp = conf->multipaths + i; @@ -303,7 +303,6 @@ static int multipath_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) p->bdev = rdev->bdev; p->operational = 1; p->used_slot = 1; - conf->nr_disks++; conf->working_disks++; err = 0; } @@ -332,7 +331,6 @@ static int multipath_remove_disk(mddev_t *mddev, int number) } p->bdev = NULL; p->used_slot = 0; - conf->nr_disks--; err = 0; } if (err) @@ -500,7 +498,6 @@ static int multipath_run (mddev_t *mddev) } conf->raid_disks = sb->raid_disks = num_rdevs; - conf->nr_disks = num_rdevs; mddev->sb_dirty = 1; conf->mddev = mddev; conf->device_lock = SPIN_LOCK_UNLOCKED; diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 6dca5c9133e4..df84c5db5e9f 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -625,8 +625,8 @@ static void print_conf(conf_t *conf) printk("(!conf)\n"); return; } - printk(" --- wd:%d rd:%d nd:%d\n", conf->working_disks, - conf->raid_disks, conf->nr_disks); + printk(" --- wd:%d rd:%d\n", conf->working_disks, + conf->raid_disks); for (i = 0; i < MD_SB_DISKS; i++) { tmp = conf->mirrors + i; @@ -803,7 +803,6 @@ static int raid1_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) p->spare = 1; p->used_slot = 1; p->head_position = 0; - conf->nr_disks++; err = 0; } if (err) @@ -829,7 +828,6 @@ static int raid1_remove_disk(mddev_t *mddev, int number) } p->bdev = NULL; p->used_slot = 0; - conf->nr_disks--; err = 0; } if (err) @@ -1279,7 +1277,6 @@ static int run(mddev_t *mddev) } } conf->raid_disks = sb->raid_disks; - conf->nr_disks = sb->nr_disks; conf->mddev = mddev; conf->device_lock = SPIN_LOCK_UNLOCKED; diff --git a/include/linux/raid/multipath.h b/include/linux/raid/multipath.h index 4b7e3c0dc792..422f19b2ab7f 100644 --- a/include/linux/raid/multipath.h +++ b/include/linux/raid/multipath.h @@ -20,7 +20,6 @@ struct multipath_info { struct multipath_private_data { mddev_t *mddev; struct multipath_info multipaths[MD_SB_DISKS]; - int nr_disks; int raid_disks; int working_disks; mdk_thread_t *thread; diff --git a/include/linux/raid/raid1.h b/include/linux/raid/raid1.h index f63d68e55c11..d0a358b47d19 100644 --- a/include/linux/raid/raid1.h +++ b/include/linux/raid/raid1.h @@ -27,7 +27,6 @@ typedef struct r1bio_s r1bio_t; struct r1_private_data_s { mddev_t *mddev; mirror_info_t mirrors[MD_SB_DISKS]; - int nr_disks; int raid_disks; int working_disks; int last_used; -- cgit v1.2.3 From 9f3b03804be20308849e4c3e31d3c1a6d2fdcdc8 Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Thu, 18 Jul 2002 19:11:00 -0700 Subject: [PATCH] MD - Remove number and raid_disk from personality arrays Remove number and raid_disk from personality arrays These are redundant. number not needed any more raid_disk never was as that is the index. --- drivers/md/multipath.c | 11 +++-------- drivers/md/raid1.c | 16 ++-------------- drivers/md/raid5.c | 18 ++---------------- include/linux/raid/multipath.h | 2 -- include/linux/raid/raid1.h | 2 -- include/linux/raid/raid5.h | 2 -- 6 files changed, 7 insertions(+), 44 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index 94c37a85ca9a..beaabf8a444b 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -279,11 +279,10 @@ static void print_multipath_conf (multipath_conf_t *conf) for (i = 0; i < MD_SB_DISKS; i++) { tmp = conf->multipaths + i; - if (tmp->operational || tmp->number || - tmp->raid_disk || tmp->used_slot) - printk(" disk%d, o:%d, n:%d rd:%d us:%d dev:%s\n", + if (tmp->operational || tmp->used_slot) + printk(" disk%d, o:%d, us:%d dev:%s\n", i,tmp->operational, - tmp->number,tmp->raid_disk,tmp->used_slot, + tmp->used_slot, bdev_partition_name(tmp->bdev)); } } @@ -298,8 +297,6 @@ static int multipath_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) print_multipath_conf(conf); spin_lock_irq(&conf->device_lock); if (!p->used_slot) { - p->number = rdev->desc_nr; - p->raid_disk = rdev->raid_disk; p->bdev = rdev->bdev; p->operational = 1; p->used_slot = 1; @@ -489,8 +486,6 @@ static int multipath_run (mddev_t *mddev) * spares. multipath_read_balance deals with choose * the "best" operational device. */ - disk->number = rdev->desc_nr; - disk->raid_disk = disk_idx; disk->bdev = rdev->bdev; disk->operational = 1; disk->used_slot = 1; diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index df84c5db5e9f..cc9a0ba5ed5d 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -630,9 +630,9 @@ static void print_conf(conf_t *conf) for (i = 0; i < MD_SB_DISKS; i++) { tmp = conf->mirrors + i; - printk(" disk %d, s:%d, o:%d, n:%d rd:%d us:%d dev:%s\n", + printk(" disk %d, s:%d, o:%d, us:%d dev:%s\n", i, tmp->spare, tmp->operational, - tmp->number, tmp->raid_disk, tmp->used_slot, + tmp->used_slot, bdev_partition_name(tmp->bdev)); } } @@ -717,8 +717,6 @@ static int raid1_spare_active(mddev_t *mddev) * give the proper raid_disk number to the now activated * disk. (this means we switch back these values) */ - xchg_values(sdisk->raid_disk, fdisk->raid_disk); - xchg_values(sdisk->number, fdisk->number); if (!sdisk->bdev) sdisk->used_slot = 0; @@ -794,8 +792,6 @@ static int raid1_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) print_conf(conf); spin_lock_irq(&conf->device_lock); if (!p->used_slot) { - p->number = rdev->desc_nr; - p->raid_disk = rdev->raid_disk; /* it will be held open by rdev */ p->bdev = rdev->bdev; p->operational = 0; @@ -1233,8 +1229,6 @@ static int run(mddev_t *mddev) disk = conf->mirrors + disk_idx; if (rdev->faulty) { - disk->number = rdev->desc_nr; - disk->raid_disk = disk_idx; disk->bdev = rdev->bdev; disk->operational = 0; disk->write_only = 0; @@ -1252,8 +1246,6 @@ static int run(mddev_t *mddev) } printk(OPERATIONAL, bdev_partition_name(rdev->bdev), disk_idx); - disk->number = rdev->desc_nr; - disk->raid_disk = disk_idx; disk->bdev = rdev->bdev; disk->operational = 1; disk->write_only = 0; @@ -1266,8 +1258,6 @@ static int run(mddev_t *mddev) * Must be a spare disk .. */ printk(SPARE, bdev_partition_name(rdev->bdev)); - disk->number = rdev->desc_nr; - disk->raid_disk = disk_idx; disk->bdev = rdev->bdev; disk->operational = 0; disk->write_only = 0; @@ -1295,8 +1285,6 @@ static int run(mddev_t *mddev) disk = conf->mirrors + i; if (!disk->used_slot) { - disk->number = i; - disk->raid_disk = i; disk->bdev = NULL; disk->operational = 0; disk->write_only = 0; diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 95a4539d90d6..e7fb96954fdd 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -1410,8 +1410,6 @@ static int run (mddev_t *mddev) if (rdev->faulty) { printk(KERN_ERR "raid5: disabled device %s (errors detected)\n", bdev_partition_name(rdev->bdev)); - disk->number = rdev->desc_nr; - disk->raid_disk = raid_disk; disk->bdev = rdev->bdev; disk->operational = 0; @@ -1427,8 +1425,6 @@ static int run (mddev_t *mddev) } printk(KERN_INFO "raid5: device %s operational as raid disk %d\n", bdev_partition_name(rdev->bdev), raid_disk); - disk->number = rdev->desc_nr; - disk->raid_disk = raid_disk; disk->bdev = rdev->bdev; disk->operational = 1; disk->used_slot = 1; @@ -1439,8 +1435,6 @@ static int run (mddev_t *mddev) * Must be a spare disk .. */ printk(KERN_INFO "raid5: spare disk %s\n", bdev_partition_name(rdev->bdev)); - disk->number = rdev->desc_nr; - disk->raid_disk = raid_disk; disk->bdev = rdev->bdev; disk->operational = 0; @@ -1454,9 +1448,6 @@ static int run (mddev_t *mddev) disk = conf->disks + i; if (!disk->used_slot) { - - disk->number = i; - disk->raid_disk = i; disk->bdev = NULL; disk->operational = 0; @@ -1634,9 +1625,9 @@ static void print_raid5_conf (raid5_conf_t *conf) for (i = 0; i < conf->working_disks+conf->failed_disks; i++) { #endif tmp = conf->disks + i; - printk(" disk %d, s:%d, o:%d, n:%d rd:%d us:%d dev:%s\n", + printk(" disk %d, s:%d, o:%d, us:%d dev:%s\n", i, tmp->spare,tmp->operational, - tmp->number,tmp->raid_disk,tmp->used_slot, + tmp->used_slot, bdev_partition_name(tmp->bdev)); } } @@ -1704,9 +1695,6 @@ static int raid5_spare_active(mddev_t *mddev) * disk. (this means we switch back these values) */ - xchg_values(sdisk->raid_disk, fdisk->raid_disk); - xchg_values(sdisk->number, fdisk->number); - if (!sdisk->bdev) sdisk->used_slot = 0; @@ -1815,8 +1803,6 @@ static int raid5_add_disk(mddev_t *mddev, mdk_rdev_t *rdev) */ if (!p->used_slot) { - p->number = rdev->desc_nr; - p->raid_disk = rdev->raid_disk; /* it will be held open by rdev */ p->bdev = rdev->bdev; p->operational = 0; diff --git a/include/linux/raid/multipath.h b/include/linux/raid/multipath.h index 422f19b2ab7f..6ceb343eedb0 100644 --- a/include/linux/raid/multipath.h +++ b/include/linux/raid/multipath.h @@ -5,8 +5,6 @@ #include struct multipath_info { - int number; - int raid_disk; struct block_device *bdev; /* diff --git a/include/linux/raid/raid1.h b/include/linux/raid/raid1.h index d0a358b47d19..28651c4d0658 100644 --- a/include/linux/raid/raid1.h +++ b/include/linux/raid/raid1.h @@ -6,8 +6,6 @@ typedef struct mirror_info mirror_info_t; struct mirror_info { - int number; - int raid_disk; struct block_device *bdev; sector_t head_position; atomic_t nr_pending; diff --git a/include/linux/raid/raid5.h b/include/linux/raid/raid5.h index 7f8beb8acdaa..7e8333a75bd4 100644 --- a/include/linux/raid/raid5.h +++ b/include/linux/raid/raid5.h @@ -194,8 +194,6 @@ struct stripe_head { struct disk_info { struct block_device *bdev; int operational; - int number; - int raid_disk; int write_only; int spare; int used_slot; -- cgit v1.2.3 From 5e601b358ca1e01ed96ab24a7511cfb79fd49401 Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Thu, 18 Jul 2002 19:11:14 -0700 Subject: [PATCH] MD - Move persistent from superblock to mddev Move persistent from superblock to mddev Tidyup calc_dev_sboffset and calc_dev_size on the way --- drivers/md/md.c | 59 ++++++++++++++++++++++------------------------- include/linux/raid/md_k.h | 2 ++ 2 files changed, 30 insertions(+), 31 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/md.c b/drivers/md/md.c index cf0bba0726cf..88468e761790 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -297,24 +297,20 @@ char * partition_name(kdev_t dev) return dname->name; } -static unsigned int calc_dev_sboffset(mdk_rdev_t *rdev, mddev_t *mddev, - int persistent) +static unsigned int calc_dev_sboffset(struct block_device *bdev) { - unsigned int size = rdev->bdev->bd_inode->i_size >> BLOCK_SIZE_BITS; - if (persistent) - size = MD_NEW_SIZE_BLOCKS(size); - return size; + unsigned int size = bdev->bd_inode->i_size >> BLOCK_SIZE_BITS; + return MD_NEW_SIZE_BLOCKS(size); } -static unsigned int calc_dev_size(mdk_rdev_t *rdev, mddev_t *mddev, int persistent) +static unsigned int calc_dev_size(struct block_device *bdev, mddev_t *mddev) { unsigned int size; - size = calc_dev_sboffset(rdev, mddev, persistent); - if (!mddev->sb) { - MD_BUG(); - return size; - } + if (mddev->persistent) + size = calc_dev_sboffset(bdev); + else + size = bdev->bd_inode->i_size >> BLOCK_SIZE_BITS; if (mddev->sb->chunk_size) size &= ~(mddev->sb->chunk_size/1024 - 1); return size; @@ -450,7 +446,7 @@ static int read_disk_sb(mdk_rdev_t * rdev) * * It also happens to be a multiple of 4Kb. */ - sb_offset = calc_dev_sboffset(rdev, rdev->mddev, 1); + sb_offset = calc_dev_sboffset(rdev->bdev); rdev->sb_offset = sb_offset; if (!sync_page_io(rdev->bdev, sb_offset<<1, MD_SB_BYTES, rdev->sb_page, READ)) @@ -814,7 +810,7 @@ static int write_disk_sb(mdk_rdev_t * rdev) return 1; } - sb_offset = calc_dev_sboffset(rdev, rdev->mddev, 1); + sb_offset = calc_dev_sboffset(rdev->bdev); if (rdev->sb_offset != sb_offset) { printk(KERN_INFO "%s's sb offset has changed from %ld to %ld, skipping\n", partition_name(dev), rdev->sb_offset, sb_offset); @@ -825,7 +821,7 @@ static int write_disk_sb(mdk_rdev_t * rdev) * its size has changed to zero silently, and the MD code does * not yet know that it's faulty. */ - size = calc_dev_size(rdev, rdev->mddev, 1); + size = calc_dev_size(rdev->bdev, rdev->mddev); if (size != rdev->size) { printk(KERN_INFO "%s's size has changed from %ld to %ld since import, skipping\n", partition_name(dev), rdev->size, size); @@ -863,6 +859,7 @@ static int sync_sbs(mddev_t * mddev) int active=0, working=0,failed=0,spare=0,nr_disks=0; sb = mddev->sb; + sb->not_persistent = !mddev->persistent; sb->disks[0].state = (1<sb->not_persistent) + if (!mddev->persistent) return; printk(KERN_INFO "md: updating md%d RAID superblock on device\n", @@ -1153,6 +1150,7 @@ static int analyze_sbs(mddev_t * mddev) } memcpy (sb, freshest->sb, sizeof(*sb)); + mddev->persistent = ! sb->not_persistent; /* * at this point we have picked the 'best' superblock * from all available superblocks. @@ -1230,7 +1228,7 @@ abort: static int device_size_calculation(mddev_t * mddev) { - int data_disks = 0, persistent; + int data_disks = 0; unsigned int readahead; mdp_super_t *sb = mddev->sb; struct list_head *tmp; @@ -1241,7 +1239,7 @@ static int device_size_calculation(mddev_t * mddev) * (we have to do this after having validated chunk_size, * because device size has to be modulo chunk_size) */ - persistent = !mddev->sb->not_persistent; + ITERATE_RDEV(mddev,rdev,tmp) { if (rdev->faulty) continue; @@ -1249,7 +1247,7 @@ static int device_size_calculation(mddev_t * mddev) MD_BUG(); continue; } - rdev->size = calc_dev_size(rdev, mddev, persistent); + rdev->size = calc_dev_size(rdev->bdev, mddev); if (rdev->size < sb->chunk_size / 1024) { printk(KERN_WARNING "md: Dev %s smaller than chunk_size: %ldk < %dk\n", @@ -1849,7 +1847,7 @@ static int get_array_info(mddev_t * mddev, void * arg) SET_FROM_SB(nr_disks); SET_FROM_SB(raid_disks); SET_FROM_SB(md_minor); - SET_FROM_SB(not_persistent); + info.not_persistent= !mddev->persistent; SET_FROM_SB(utime); SET_FROM_SB(state); @@ -1911,7 +1909,7 @@ static int get_disk_info(mddev_t * mddev, void * arg) static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info) { - int size, persistent; + int size; mdk_rdev_t *rdev; kdev_t dev; dev = mk_kdev(info->major,info->minor); @@ -1958,12 +1956,11 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info) bind_rdev_to_array(rdev, mddev); - persistent = !mddev->sb->not_persistent; - if (!persistent) + if (!mddev->persistent) printk(KERN_INFO "md: nonpersistent superblock ...\n"); - size = calc_dev_size(rdev, mddev, persistent); - rdev->sb_offset = calc_dev_sboffset(rdev, mddev, persistent); + size = calc_dev_size(rdev->bdev, mddev); + rdev->sb_offset = calc_dev_sboffset(rdev->bdev); if (!mddev->sb->size || (mddev->sb->size > size)) mddev->sb->size = size; @@ -2053,7 +2050,7 @@ busy: static int hot_add_disk(mddev_t * mddev, kdev_t dev) { - int i, err, persistent; + int i, err; unsigned int size; mdk_rdev_t *rdev; @@ -2074,8 +2071,8 @@ static int hot_add_disk(mddev_t * mddev, kdev_t dev) printk(KERN_WARNING "md: error, md_import_device() returned %ld\n", PTR_ERR(rdev)); return -EINVAL; } - persistent = !mddev->sb->not_persistent; - size = calc_dev_size(rdev, mddev, persistent); + + size = calc_dev_size(rdev->bdev, mddev); if (size < mddev->sb->size) { printk(KERN_WARNING "md%d: disk size %d blocks < array size %d\n", @@ -2098,7 +2095,7 @@ static int hot_add_disk(mddev_t * mddev, kdev_t dev) * noticed in interrupt contexts ... */ rdev->size = size; - rdev->sb_offset = calc_dev_sboffset(rdev, mddev, persistent); + rdev->sb_offset = calc_dev_sboffset(rdev->bdev); for (i = mddev->sb->raid_disks; i < MD_SB_DISKS; i++) if (find_rdev_nr(mddev,i)==NULL) @@ -2155,7 +2152,7 @@ static int set_array_info(mddev_t * mddev, mdu_array_info_t *info) SET_SB(nr_disks); SET_SB(raid_disks); SET_SB(md_minor); - SET_SB(not_persistent); + mddev->persistent = ! info->not_persistent; SET_SB(state); @@ -3329,7 +3326,7 @@ static struct { * invoked program now). Added ability to initialise all * the MD devices (by specifying multiple "md=" lines) * instead of just one. -- KTK - * 18May2000: Added support for persistant-superblock arrays: + * 18May2000: Added support for persistent-superblock arrays: * md=n,0,factor,fault,device-list uses RAID0 for device n * md=n,-1,factor,fault,device-list uses LINEAR for device n * md=n,device-list reads a RAID superblock from the devices diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h index 6b6845e8fd82..9ddabfde79da 100644 --- a/include/linux/raid/md_k.h +++ b/include/linux/raid/md_k.h @@ -175,6 +175,8 @@ struct mddev_s int sb_dirty; int ro; + int persistent; + struct mdk_thread_s *sync_thread; /* doing resync or reconstruct */ unsigned long curr_resync; /* blocks scheduled */ unsigned long resync_mark; /* a recent timestamp */ -- cgit v1.2.3 From bab5d712e332ea0b68aa289cd730446c679216e2 Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Thu, 18 Jul 2002 19:11:27 -0700 Subject: [PATCH] MD - Remove dependance on superblock Remove dependance on superblock All the remaining field of interest in the superblock get duplicated in the mddev struture and this is treated as authoritative. The superblock gets completely generated at write time, and all useful information extracted at read time. This means that we can slot in different superblock formats without affecting the bulk of the code. --- drivers/md/linear.c | 6 +- drivers/md/md.c | 203 ++++++++++++++++++++++++++-------------------- drivers/md/multipath.c | 13 ++- drivers/md/raid0.c | 10 +-- drivers/md/raid1.c | 11 ++- drivers/md/raid5.c | 30 +++---- include/linux/raid/md_k.h | 13 +++ 7 files changed, 160 insertions(+), 126 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/linear.c b/drivers/md/linear.c index 5487ce306d71..f85bf19ce7a7 100644 --- a/drivers/md/linear.c +++ b/drivers/md/linear.c @@ -55,7 +55,7 @@ static int linear_run (mddev_t *mddev) int j = rdev->raid_disk; dev_info_t *disk = conf->disks + j; - if (j < 0 || j > mddev->sb->raid_disks || disk->bdev) { + if (j < 0 || j > mddev->raid_disks || disk->bdev) { printk("linear: disk numbering problem. Aborting!\n"); goto out; } @@ -67,7 +67,7 @@ static int linear_run (mddev_t *mddev) conf->smallest = disk; cnt++; } - if (cnt != mddev->sb->raid_disks) { + if (cnt != mddev->raid_disks) { printk("linear: not enough drives present. Aborting!\n"); goto out; } @@ -186,7 +186,7 @@ static int linear_status (char *page, mddev_t *mddev) } sz += sprintf(page+sz, "\n"); #endif - sz += sprintf(page+sz, " %dk rounding", mddev->sb->chunk_size/1024); + sz += sprintf(page+sz, " %dk rounding", mddev->chunk_size/1024); return sz; } diff --git a/drivers/md/md.c b/drivers/md/md.c index 88468e761790..e6386582cf69 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -311,8 +311,8 @@ static unsigned int calc_dev_size(struct block_device *bdev, mddev_t *mddev) size = calc_dev_sboffset(bdev); else size = bdev->bd_inode->i_size >> BLOCK_SIZE_BITS; - if (mddev->sb->chunk_size) - size &= ~(mddev->sb->chunk_size/1024 - 1); + if (mddev->chunk_size) + size &= ~(mddev->chunk_size/1024 - 1); return size; } @@ -322,14 +322,10 @@ static unsigned int zoned_raid_size(mddev_t *mddev) mdk_rdev_t * rdev; struct list_head *tmp; - if (!mddev->sb) { - MD_BUG(); - return -EINVAL; - } /* * do size and offset calculations. */ - mask = ~(mddev->sb->chunk_size/1024 - 1); + mask = ~(mddev->chunk_size/1024 - 1); ITERATE_RDEV(mddev,rdev,tmp) { rdev->size &= mask; @@ -859,7 +855,31 @@ static int sync_sbs(mddev_t * mddev) int active=0, working=0,failed=0,spare=0,nr_disks=0; sb = mddev->sb; + memset(sb, 0, sizeof(*sb)); + + sb->md_magic = MD_SB_MAGIC; + sb->major_version = mddev->major_version; + sb->minor_version = mddev->minor_version; + sb->patch_version = mddev->patch_version; + sb->gvalid_words = 0; /* ignored */ + memcpy(&sb->set_uuid0, mddev->uuid+0, 4); + memcpy(&sb->set_uuid1, mddev->uuid+4, 4); + memcpy(&sb->set_uuid2, mddev->uuid+8, 4); + memcpy(&sb->set_uuid3, mddev->uuid+12,4); + + sb->ctime = mddev->ctime; + sb->level = mddev->level; + sb->size = mddev->size; + sb->raid_disks = mddev->raid_disks; + sb->md_minor = mddev->__minor; sb->not_persistent = !mddev->persistent; + sb->utime = mddev->utime; + sb->state = mddev->state; + sb->events_hi = (mddev->events>>32); + sb->events_lo = (u32)mddev->events; + + sb->layout = mddev->layout; + sb->chunk_size = mddev->chunk_size; sb->disks[0].state = (1<sb_dirty = 0; repeat: - mddev->sb->utime = CURRENT_TIME; - if (!(++mddev->sb->events_lo)) - ++mddev->sb->events_hi; + mddev->utime = CURRENT_TIME; + mddev->events ++; - if (!(mddev->sb->events_lo | mddev->sb->events_hi)) { + if (!mddev->events) { /* * oops, this 64-bit counter should never wrap. * Either we are in around ~1 trillion A.C., assuming * 1 reboot per second, or we have a bug: */ MD_BUG(); - mddev->sb->events_lo = mddev->sb->events_hi = 0xffffffff; + mddev->events --; } sync_sbs(mddev); @@ -1150,7 +1169,25 @@ static int analyze_sbs(mddev_t * mddev) } memcpy (sb, freshest->sb, sizeof(*sb)); + mddev->major_version = sb->major_version; + mddev->minor_version = sb->minor_version; + mddev->patch_version = sb->patch_version; mddev->persistent = ! sb->not_persistent; + mddev->chunk_size = sb->chunk_size; + mddev->ctime = sb->ctime; + mddev->utime = sb->utime; + mddev->level = sb->level; + mddev->layout = sb->layout; + mddev->raid_disks = sb->raid_disks; + mddev->state = sb->state; + mddev->size = sb->size; + mddev->events = md_event(sb); + + memcpy(mddev->uuid+0, &sb->set_uuid0, 4); + memcpy(mddev->uuid+4, &sb->set_uuid1, 4); + memcpy(mddev->uuid+8, &sb->set_uuid2, 4); + memcpy(mddev->uuid+12,&sb->set_uuid3, 4); + /* * at this point we have picked the 'best' superblock * from all available superblocks. @@ -1161,11 +1198,10 @@ static int analyze_sbs(mddev_t * mddev) /* * Kick all non-fresh devices */ - __u64 ev1, ev2; + __u64 ev1; ev1 = md_event(rdev->sb); - ev2 = md_event(sb); ++ev1; - if (ev1 < ev2) { + if (ev1 < mddev->events) { printk(KERN_WARNING "md: kicking non-fresh %s from array!\n", partition_name(rdev->dev)); kick_rdev_from_array(rdev); @@ -1179,7 +1215,7 @@ static int analyze_sbs(mddev_t * mddev) */ i = 0; ITERATE_RDEV(mddev,rdev,tmp) { - if (sb->level == LEVEL_MULTIPATH) { + if (mddev->level == LEVEL_MULTIPATH) { rdev->alias_device = !!i; rdev->desc_nr = i++; rdev->raid_disk = rdev->desc_nr; @@ -1195,7 +1231,7 @@ static int analyze_sbs(mddev_t * mddev) rdev->faulty = 1; kick_rdev_from_array(rdev); } else if (desc->state & (1<raid_disk < mddev->sb->raid_disks) + rdev->raid_disk < mddev->raid_disks) rdev->in_sync = 1; } } @@ -1204,16 +1240,16 @@ static int analyze_sbs(mddev_t * mddev) /* * Check if we can support this RAID array */ - if (sb->major_version != MD_MAJOR_VERSION || - sb->minor_version > MD_MINOR_VERSION) { + if (mddev->major_version != MD_MAJOR_VERSION || + mddev->minor_version > MD_MINOR_VERSION) { - printk(OLD_VERSION, mdidx(mddev), sb->major_version, - sb->minor_version, sb->patch_version); + printk(OLD_VERSION, mdidx(mddev), mddev->major_version, + mddev->minor_version, mddev->patch_version); goto abort; } - if ((sb->state != (1 << MD_SB_CLEAN)) && ((sb->level == 1) || - (sb->level == 4) || (sb->level == 5))) + if ((mddev->state != (1 << MD_SB_CLEAN)) && ((mddev->level == 1) || + (mddev->level == 4) || (mddev->level == 5))) printk(NOT_CLEAN_IGNORE, mdidx(mddev)); return 0; @@ -1230,7 +1266,6 @@ static int device_size_calculation(mddev_t * mddev) { int data_disks = 0; unsigned int readahead; - mdp_super_t *sb = mddev->sb; struct list_head *tmp; mdk_rdev_t *rdev; @@ -1248,16 +1283,16 @@ static int device_size_calculation(mddev_t * mddev) continue; } rdev->size = calc_dev_size(rdev->bdev, mddev); - if (rdev->size < sb->chunk_size / 1024) { + if (rdev->size < mddev->chunk_size / 1024) { printk(KERN_WARNING "md: Dev %s smaller than chunk_size: %ldk < %dk\n", partition_name(rdev->dev), - rdev->size, sb->chunk_size / 1024); + rdev->size, mddev->chunk_size / 1024); return -EINVAL; } } - switch (sb->level) { + switch (mddev->level) { case LEVEL_MULTIPATH: data_disks = 1; break; @@ -1273,30 +1308,30 @@ static int device_size_calculation(mddev_t * mddev) break; case 0: zoned_raid_size(mddev); - data_disks = sb->raid_disks; + data_disks = mddev->raid_disks; break; case 1: data_disks = 1; break; case 4: case 5: - data_disks = sb->raid_disks-1; + data_disks = mddev->raid_disks-1; break; default: - printk(UNKNOWN_LEVEL, mdidx(mddev), sb->level); + printk(UNKNOWN_LEVEL, mdidx(mddev), mddev->level); goto abort; } if (!md_size[mdidx(mddev)]) - md_size[mdidx(mddev)] = sb->size * data_disks; + md_size[mdidx(mddev)] = mddev->size * data_disks; readahead = (VM_MAX_READAHEAD * 1024) / PAGE_SIZE; - if (!sb->level || (sb->level == 4) || (sb->level == 5)) { - readahead = (mddev->sb->chunk_size>>PAGE_SHIFT) * 4 * data_disks; + if (!mddev->level || (mddev->level == 4) || (mddev->level == 5)) { + readahead = (mddev->chunk_size>>PAGE_SHIFT) * 4 * data_disks; if (readahead < data_disks * (MAX_SECTORS>>(PAGE_SHIFT-9))*2) readahead = data_disks * (MAX_SECTORS>>(PAGE_SHIFT-9))*2; } else { // (no multipath branch - it uses the default setting) - if (sb->level == -3) + if (mddev->level == -3) readahead = 0; } @@ -1351,8 +1386,8 @@ static int do_md_run(mddev_t * mddev) return -EINVAL; } - chunk_size = mddev->sb->chunk_size; - pnum = level_to_pers(mddev->sb->level); + chunk_size = mddev->chunk_size; + pnum = level_to_pers(mddev->level); if ((pnum != MULTIPATH) && (pnum != RAID1)) { if (!chunk_size) { @@ -1383,7 +1418,7 @@ static int do_md_run(mddev_t * mddev) } else if (chunk_size) printk(KERN_INFO "md: RAID level %d does not need chunksize! Continuing anyway.\n", - mddev->sb->level); + mddev->level); if (pnum >= MAX_PERSONALITY) { MD_BUG(); @@ -1443,12 +1478,12 @@ static int do_md_run(mddev_t * mddev) return -EINVAL; } - mddev->in_sync = (mddev->sb->state & (1<in_sync = (mddev->state & (1<pers->sync_request) - mddev->sb->state &= ~(1 << MD_SB_CLEAN); + mddev->state &= ~(1 << MD_SB_CLEAN); md_update_sb(mddev); md_recover_arrays(); @@ -1556,7 +1591,7 @@ static int do_md_stop(mddev_t * mddev, int ro) */ if (mddev->in_sync) { printk(KERN_INFO "md: marking sb clean...\n"); - mddev->sb->state |= 1 << MD_SB_CLEAN; + mddev->state |= 1 << MD_SB_CLEAN; } md_update_sb(mddev); } @@ -1812,7 +1847,6 @@ static int get_version(void * arg) return 0; } -#define SET_FROM_SB(x) info.x = mddev->sb->x static int get_array_info(mddev_t * mddev, void * arg) { mdu_array_info_t info; @@ -1820,10 +1854,6 @@ static int get_array_info(mddev_t * mddev, void * arg) mdk_rdev_t *rdev; struct list_head *tmp; - if (!mddev->sb) { - MD_BUG(); - return -EINVAL; - } nr=working=active=failed=spare=0; ITERATE_RDEV(mddev,rdev,tmp) { nr++; @@ -1838,26 +1868,27 @@ static int get_array_info(mddev_t * mddev, void * arg) } } - SET_FROM_SB(major_version); - SET_FROM_SB(minor_version); - SET_FROM_SB(patch_version); - SET_FROM_SB(ctime); - SET_FROM_SB(level); - SET_FROM_SB(size); - SET_FROM_SB(nr_disks); - SET_FROM_SB(raid_disks); - SET_FROM_SB(md_minor); + info.major_version = mddev->major_version; + info.major_version = mddev->major_version; + info.minor_version = mddev->minor_version; + info.patch_version = mddev->patch_version; + info.ctime = mddev->ctime; + info.level = mddev->level; + info.size = mddev->size; + info.nr_disks = nr; + info.raid_disks = mddev->raid_disks; + info.md_minor = mddev->__minor; info.not_persistent= !mddev->persistent; - SET_FROM_SB(utime); - SET_FROM_SB(state); + info.utime = mddev->utime; + info.state = mddev->state; info.active_disks = active; info.working_disks = working; info.failed_disks = failed; info.spare_disks = spare; - SET_FROM_SB(layout); - SET_FROM_SB(chunk_size); + info.layout = mddev->layout; + info.chunk_size = mddev->chunk_size; if (copy_to_user(arg, &info, sizeof(info))) return -EFAULT; @@ -1873,9 +1904,6 @@ static int get_disk_info(mddev_t * mddev, void * arg) unsigned int nr; mdk_rdev_t *rdev; - if (!mddev->sb) - return -EINVAL; - if (copy_from_user(&info, arg, sizeof(info))) return -EFAULT; @@ -1949,7 +1977,7 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info) rdev->desc_nr = info->number; rdev->raid_disk = info->raid_disk; rdev->faulty = 0; - if (rdev->raid_disk < mddev->sb->raid_disks) + if (rdev->raid_disk < mddev->raid_disks) rdev->in_sync = (info->state & (1<in_sync = 0; @@ -1962,8 +1990,8 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info) size = calc_dev_size(rdev->bdev, mddev); rdev->sb_offset = calc_dev_sboffset(rdev->bdev); - if (!mddev->sb->size || (mddev->sb->size > size)) - mddev->sb->size = size; + if (!mddev->size || (mddev->size > size)) + mddev->size = size; } return 0; @@ -2074,9 +2102,9 @@ static int hot_add_disk(mddev_t * mddev, kdev_t dev) size = calc_dev_size(rdev->bdev, mddev); - if (size < mddev->sb->size) { - printk(KERN_WARNING "md%d: disk size %d blocks < array size %d\n", - mdidx(mddev), size, mddev->sb->size); + if (size < mddev->size) { + printk(KERN_WARNING "md%d: disk size %d blocks < array size %ld\n", + mdidx(mddev), size, mddev->size); err = -ENOSPC; goto abort_export; } @@ -2097,7 +2125,7 @@ static int hot_add_disk(mddev_t * mddev, kdev_t dev) rdev->size = size; rdev->sb_offset = calc_dev_sboffset(rdev->bdev); - for (i = mddev->sb->raid_disks; i < MD_SB_DISKS; i++) + for (i = mddev->raid_disks; i < MD_SB_DISKS; i++) if (find_rdev_nr(mddev,i)==NULL) break; @@ -2135,43 +2163,38 @@ abort_export: return err; } -#define SET_SB(x) mddev->sb->x = info->x static int set_array_info(mddev_t * mddev, mdu_array_info_t *info) { if (alloc_array_sb(mddev)) return -ENOMEM; - mddev->sb->major_version = MD_MAJOR_VERSION; - mddev->sb->minor_version = MD_MINOR_VERSION; - mddev->sb->patch_version = MD_PATCHLEVEL_VERSION; - mddev->sb->ctime = CURRENT_TIME; + mddev->major_version = MD_MAJOR_VERSION; + mddev->minor_version = MD_MINOR_VERSION; + mddev->patch_version = MD_PATCHLEVEL_VERSION; + mddev->ctime = CURRENT_TIME; - SET_SB(level); - SET_SB(size); - SET_SB(nr_disks); - SET_SB(raid_disks); - SET_SB(md_minor); + mddev->level = info->level; + mddev->size = info->size; + mddev->raid_disks = info->raid_disks; + /* don't set __minor, it is determined by which /dev/md* was + * openned + */ + mddev->state = info->state; mddev->persistent = ! info->not_persistent; - SET_SB(state); + mddev->layout = info->layout; + mddev->chunk_size = info->chunk_size; - SET_SB(layout); - SET_SB(chunk_size); - mddev->sb->md_magic = MD_SB_MAGIC; /* * Generate a 128 bit UUID */ - get_random_bytes(&mddev->sb->set_uuid0, 4); - get_random_bytes(&mddev->sb->set_uuid1, 4); - get_random_bytes(&mddev->sb->set_uuid2, 4); - get_random_bytes(&mddev->sb->set_uuid3, 4); + get_random_bytes(mddev->uuid, 16); return 0; } -#undef SET_SB static int set_disk_faulty(mddev_t *mddev, kdev_t dev) { @@ -2680,7 +2703,7 @@ static int status_resync(char * page, mddev_t * mddev) unsigned long max_blocks, resync, res, dt, db, rt; resync = (mddev->curr_resync - atomic_read(&mddev->recovery_active))/2; - max_blocks = mddev->sb->size; + max_blocks = mddev->size; /* * Should not happen. @@ -2939,7 +2962,7 @@ static void md_do_sync(void *data) } } while (mddev->curr_resync < 2); - max_sectors = mddev->sb->size << 1; + max_sectors = mddev->size << 1; printk(KERN_INFO "md: syncing RAID array md%d\n", mdidx(mddev)); printk(KERN_INFO "md: minimum _guaranteed_ reconstruction speed: %d KB/sec/disc.\n", sysctl_speed_limit_min); @@ -3491,7 +3514,7 @@ void __init md_setup_drive(void) dinfo.state = (1<sb->raid_disks++; + mddev->raid_disks++; err = add_new_disk (mddev, &dinfo); } } else { diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c index beaabf8a444b..13c1201dd6c0 100644 --- a/drivers/md/multipath.c +++ b/drivers/md/multipath.c @@ -424,7 +424,7 @@ static void multipathd (void *data) "multipath: detected IO path differences!\n" #define ARRAY_IS_ACTIVE KERN_INFO \ -"multipath: array md%d active with %d out of %d IO paths (%d spare IO paths)\n" +"multipath: array md%d active with %d out of %d IO paths\n" #define THREAD_ERROR KERN_ERR \ "multipath: couldn't allocate thread for md%d\n" @@ -434,15 +434,14 @@ static int multipath_run (mddev_t *mddev) multipath_conf_t *conf; int disk_idx; struct multipath_info *disk; - mdp_super_t *sb = mddev->sb; mdk_rdev_t *rdev; struct list_head *tmp; int num_rdevs = 0; MOD_INC_USE_COUNT; - if (sb->level != LEVEL_MULTIPATH) { - printk(INVALID_LEVEL, mdidx(mddev), sb->level); + if (mddev->level != LEVEL_MULTIPATH) { + printk(INVALID_LEVEL, mdidx(mddev), mddev->level); goto out; } /* @@ -492,7 +491,7 @@ static int multipath_run (mddev_t *mddev) num_rdevs++; } - conf->raid_disks = sb->raid_disks = num_rdevs; + conf->raid_disks = mddev->raid_disks = num_rdevs; mddev->sb_dirty = 1; conf->mddev = mddev; conf->device_lock = SPIN_LOCK_UNLOCKED; @@ -520,8 +519,8 @@ static int multipath_run (mddev_t *mddev) } } - printk(ARRAY_IS_ACTIVE, mdidx(mddev), sb->active_disks, - sb->raid_disks, sb->spare_disks); + printk(ARRAY_IS_ACTIVE, mdidx(mddev), conf->working_disks, + mddev->raid_disks); /* * Ok, everything is just fine now */ diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c index 2dd6e9d5f985..db063c610e79 100644 --- a/drivers/md/raid0.c +++ b/drivers/md/raid0.c @@ -89,7 +89,7 @@ static int create_strip_zones (mddev_t *mddev) ITERATE_RDEV(mddev, rdev1, tmp1) { int j = rdev1->sb->this_disk.raid_disk; - if (j < 0 || j >= mddev->sb->raid_disks) { + if (j < 0 || j >= mddev->raid_disks) { printk("raid0: bad disk number %d - aborting!\n", j); goto abort; } @@ -102,9 +102,9 @@ static int create_strip_zones (mddev_t *mddev) smallest = rdev1; cnt++; } - if (cnt != mddev->sb->raid_disks) { + if (cnt != mddev->raid_disks) { printk("raid0: too few disks (%d of %d) - aborting!\n", cnt, - mddev->sb->raid_disks); + mddev->raid_disks); goto abort; } zone->nb_dev = cnt; @@ -271,7 +271,7 @@ static int raid0_make_request (request_queue_t *q, struct bio *bio) mdk_rdev_t *tmp_dev; unsigned long chunk, block, rsect; - chunk_size = mddev->sb->chunk_size >> 10; + chunk_size = mddev->chunk_size >> 10; chunksize_bits = ffz(~chunk_size); block = bio->bi_sector >> 1; hash = conf->hash_table + block / conf->smallest->size; @@ -360,7 +360,7 @@ static int raid0_status (char *page, mddev_t *mddev) conf->strip_zone[j].size); } #endif - sz += sprintf(page + sz, " %dk chunks", mddev->sb->chunk_size/1024); + sz += sprintf(page + sz, " %dk chunks", mddev->chunk_size/1024); return sz; } diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index cc9a0ba5ed5d..a99ae86fc24a 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -1060,7 +1060,7 @@ static int sync_request(mddev_t *mddev, sector_t sector_nr, int go_faster) if (init_resync(conf)) return -ENOMEM; - max_sector = mddev->sb->size << 1; + max_sector = mddev->size << 1; if (sector_nr >= max_sector) { close_sync(conf); return 0; @@ -1180,14 +1180,13 @@ static int run(mddev_t *mddev) conf_t *conf; int i, j, disk_idx; mirror_info_t *disk; - mdp_super_t *sb = mddev->sb; mdk_rdev_t *rdev; struct list_head *tmp; MOD_INC_USE_COUNT; - if (sb->level != 1) { - printk(INVALID_LEVEL, mdidx(mddev), sb->level); + if (mddev->level != 1) { + printk(INVALID_LEVEL, mdidx(mddev), mddev->level); goto out; } /* @@ -1266,7 +1265,7 @@ static int run(mddev_t *mddev) disk->head_position = 0; } } - conf->raid_disks = sb->raid_disks; + conf->raid_disks = mddev->raid_disks; conf->mddev = mddev; conf->device_lock = SPIN_LOCK_UNLOCKED; @@ -1316,7 +1315,7 @@ static int run(mddev_t *mddev) } } - printk(ARRAY_IS_ACTIVE, mdidx(mddev), sb->raid_disks - mddev->degraded, sb->raid_disks); + printk(ARRAY_IS_ACTIVE, mdidx(mddev), mddev->raid_disks - mddev->degraded, mddev->raid_disks); /* * Ok, everything is just fine now */ diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index e7fb96954fdd..e318afa3f34d 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -1290,7 +1290,7 @@ static int sync_request (mddev_t *mddev, sector_t sector_nr, int go_faster) int raid_disks = conf->raid_disks; int data_disks = raid_disks-1; - if (sector_nr >= mddev->sb->size <<1) + if (sector_nr >= mddev->size <<1) /* just being told to finish up .. nothing to do */ return 0; @@ -1364,15 +1364,14 @@ static int run (mddev_t *mddev) { raid5_conf_t *conf; int i, raid_disk, memory; - mdp_super_t *sb = mddev->sb; mdk_rdev_t *rdev; struct disk_info *disk; struct list_head *tmp; MOD_INC_USE_COUNT; - if (sb->level != 5 && sb->level != 4) { - printk("raid5: md%d: raid level not set to 4/5 (%d)\n", mdidx(mddev), sb->level); + if (mddev->level != 5 && mddev->level != 4) { + printk("raid5: md%d: raid level not set to 4/5 (%d)\n", mdidx(mddev), mddev->level); MOD_DEC_USE_COUNT; return -EIO; } @@ -1444,7 +1443,7 @@ static int run (mddev_t *mddev) } } - for (i = 0; i < sb->raid_disks; i++) { + for (i = 0; i < conf->raid_disks; i++) { disk = conf->disks + i; if (!disk->used_slot) { @@ -1457,15 +1456,15 @@ static int run (mddev_t *mddev) } } - conf->raid_disks = sb->raid_disks; + conf->raid_disks = mddev->raid_disks; /* * 0 for a fully functional array, 1 for a degraded array. */ mddev->degraded = conf->failed_disks = conf->raid_disks - conf->working_disks; conf->mddev = mddev; - conf->chunk_size = sb->chunk_size; - conf->level = sb->level; - conf->algorithm = sb->layout; + conf->chunk_size = mddev->chunk_size; + conf->level = mddev->level; + conf->algorithm = mddev->layout; conf->max_nr_stripes = NR_STRIPES; #if 0 @@ -1490,7 +1489,7 @@ static int run (mddev_t *mddev) } if (mddev->degraded == 1 && - !(sb->state & (1<state & (1<working_disks == conf->raid_disks) - printk("raid5: raid level %d set md%d active with %d out of %d devices, algorithm %d\n", conf->level, mdidx(mddev), sb->active_disks, sb->raid_disks, conf->algorithm); + if (mddev->degraded == 0) + printk("raid5: raid level %d set md%d active with %d out of %d devices, algorithm %d\n", conf->level, mdidx(mddev), + mddev->raid_disks-mddev->degraded, mddev->raid_disks, conf->algorithm); else - printk(KERN_ALERT "raid5: raid level %d set md%d active with %d out of %d devices, algorithm %d\n", conf->level, mdidx(mddev), sb->active_disks, sb->raid_disks, conf->algorithm); + printk(KERN_ALERT "raid5: raid level %d set md%d active with %d out of %d devices, algorithm %d\n", conf->level, mdidx(mddev), + mddev->raid_disks = mddev->degraded, mddev->raid_disks, conf->algorithm); print_raid5_conf(conf); @@ -1590,10 +1591,9 @@ static void printall (raid5_conf_t *conf) static int status (char *page, mddev_t *mddev) { raid5_conf_t *conf = (raid5_conf_t *) mddev->private; - mdp_super_t *sb = mddev->sb; int sz = 0, i; - sz += sprintf (page+sz, " level %d, %dk chunk, algorithm %d", sb->level, sb->chunk_size >> 10, sb->layout); + sz += sprintf (page+sz, " level %d, %dk chunk, algorithm %d", mddev->level, mddev->chunk_size >> 10, mddev->layout); sz += sprintf (page+sz, " [%d/%d] [", conf->raid_disks, conf->working_disks); for (i = 0; i < conf->raid_disks; i++) sz += sprintf (page+sz, "%s", conf->disks[i].operational ? "U" : "_"); diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h index 9ddabfde79da..f7da358ca006 100644 --- a/include/linux/raid/md_k.h +++ b/include/linux/raid/md_k.h @@ -175,7 +175,20 @@ struct mddev_s int sb_dirty; int ro; + /* Superblock information */ + int major_version, + minor_version, + patch_version; int persistent; + int chunk_size; + time_t ctime, utime; + int level, layout; + int raid_disks; + unsigned long state; + sector_t size; /* used size of component devices */ + __u64 events; + + char uuid[16]; struct mdk_thread_s *sync_thread; /* doing resync or reconstruct */ unsigned long curr_resync; /* blocks scheduled */ -- cgit v1.2.3 From 43fb3e86ed3bba76d3b9c092cac7d47d684c729d Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Thu, 18 Jul 2002 19:11:45 -0700 Subject: [PATCH] MD - Remove the sb from the mddev Remove the sb from the mddev Now that al the important information is in mddev, we don't need to have an sb off the mddev. We only keep the per-device ones. Previously we determined if "set_array_info" had been run byb checking mddev->sb. Now we check mddev->raid_disks on the assumption that any valid array MUST have a non-zero number of devices. --- drivers/md/md.c | 87 ++++++++++++++++++----------------------------- include/linux/raid/md_k.h | 1 - 2 files changed, 33 insertions(+), 55 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/md.c b/drivers/md/md.c index e6386582cf69..8af4abc1ea4b 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -175,7 +175,7 @@ static void mddev_put(mddev_t *mddev) { if (!atomic_dec_and_lock(&mddev->active, &all_mddevs_lock)) return; - if (!mddev->sb && list_empty(&mddev->disks)) { + if (!mddev->raid_disks && list_empty(&mddev->disks)) { list_del(&mddev->all_mddevs); mddev_map[mdidx(mddev)] = NULL; kfree(mddev); @@ -350,20 +350,6 @@ static unsigned int zoned_raid_size(mddev_t *mddev) #define BAD_CSUM KERN_WARNING \ "md: invalid superblock checksum on %s\n" -static int alloc_array_sb(mddev_t * mddev) -{ - if (mddev->sb) { - MD_BUG(); - return 0; - } - - mddev->sb = (mdp_super_t *) __get_free_page (GFP_KERNEL); - if (!mddev->sb) - return -ENOMEM; - clear_page(mddev->sb); - return 0; -} - static int alloc_disk_sb(mdk_rdev_t * rdev) { if (rdev->sb_page) @@ -624,12 +610,6 @@ static void export_array(mddev_t *mddev) { struct list_head *tmp; mdk_rdev_t *rdev; - mdp_super_t *sb = mddev->sb; - - if (mddev->sb) { - mddev->sb = NULL; - free_page((unsigned long) sb); - } ITERATE_RDEV(mddev,rdev,tmp) { if (!rdev->mddev) { @@ -640,6 +620,7 @@ static void export_array(mddev_t *mddev) } if (!list_empty(&mddev->disks)) MD_BUG(); + mddev->raid_disks = 0; } static void free_mddev(mddev_t *mddev) @@ -726,12 +707,6 @@ void md_print_devices(void) ITERATE_RDEV(mddev,rdev,tmp2) printk("<%s>", partition_name(rdev->dev)); - if (mddev->sb) { - printk(" array superblock:\n"); - print_sb(mddev->sb); - } else - printk(" no array superblock.\n"); - ITERATE_RDEV(mddev,rdev,tmp2) print_rdev(rdev); } @@ -835,13 +810,16 @@ fail: return 1; } -static int sync_sbs(mddev_t * mddev) +static void sync_sbs(mddev_t * mddev) { mdk_rdev_t *rdev; mdp_super_t *sb; struct list_head *tmp; - /* make sb->disks match mddev->disks + /* make all rdev->sb match mddev data.. + * we setup the data in the first rdev and copy it + * to the others. + * * 1/ zero out disks * 2/ Add info for each disk, keeping track of highest desc_nr * 3/ any empty disks < highest become removed @@ -854,7 +832,13 @@ static int sync_sbs(mddev_t * mddev) int i; int active=0, working=0,failed=0,spare=0,nr_disks=0; - sb = mddev->sb; + if (list_empty(&mddev->disks)) { + MD_BUG(); + return; + } + rdev = list_entry(&mddev->disks.next, mdk_rdev_t, same_set); + sb = rdev->sb; + memset(sb, 0, sizeof(*sb)); sb->md_magic = MD_SB_MAGIC; @@ -922,14 +906,16 @@ static int sync_sbs(mddev_t * mddev) sb->spare_disks = spare; ITERATE_RDEV(mddev,rdev,tmp) { + mdp_super_t *this_sb; + if (rdev->faulty || rdev->alias_device) continue; - sb = rdev->sb; - *sb = *mddev->sb; - sb->this_disk = sb->disks[rdev->desc_nr]; - sb->sb_csum = calc_sb_csum(sb); + this_sb = rdev->sb; + if (this_sb != sb) + *this_sb = *sb; + this_sb->this_disk = this_sb->disks[rdev->desc_nr]; + this_sb->sb_csum = calc_sb_csum(this_sb); } - return 0; } static void md_update_sb(mddev_t * mddev) @@ -1127,9 +1113,6 @@ static int analyze_sbs(mddev_t * mddev) * find the freshest superblock, that one will be the superblock * that represents the whole array. */ - if (alloc_array_sb(mddev)) - goto abort; - sb = mddev->sb; freshest = NULL; ITERATE_RDEV(mddev,rdev,tmp) { @@ -1167,7 +1150,8 @@ static int analyze_sbs(mddev_t * mddev) printk(OUT_OF_DATE); printk(KERN_INFO "md: freshest: %s\n", partition_name(freshest->dev)); } - memcpy (sb, freshest->sb, sizeof(*sb)); + + sb = freshest->sb; mddev->major_version = sb->major_version; mddev->minor_version = sb->minor_version; @@ -1381,7 +1365,7 @@ static int do_md_run(mddev_t * mddev) /* * Analyze all RAID superblock(s) */ - if (!mddev->sb && analyze_sbs(mddev)) { + if (!mddev->raid_disks && analyze_sbs(mddev)) { MD_BUG(); return -EINVAL; } @@ -1584,7 +1568,7 @@ static int do_md_stop(mddev_t * mddev, int ro) if (mddev->ro) mddev->ro = 0; } - if (mddev->sb) { + if (mddev->raid_disks) { /* * mark it clean only if there was no resync * interrupted. @@ -1707,7 +1691,7 @@ static void autorun_devices(void) if (mddev_lock(mddev)) printk(KERN_WARNING "md: md%d locked, cannot run\n", mdidx(mddev)); - else if (mddev->sb || !list_empty(&mddev->disks)) { + else if (mddev->raid_disks || !list_empty(&mddev->disks)) { printk(KERN_WARNING "md: md%d already running, cannot run %s\n", mdidx(mddev), partition_name(rdev0->dev)); mddev_unlock(mddev); @@ -1941,7 +1925,7 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info) mdk_rdev_t *rdev; kdev_t dev; dev = mk_kdev(info->major,info->minor); - if (!mddev->sb) { + if (!mddev->raid_disks) { /* expecting a device which has a superblock */ rdev = md_import_device(dev, 1); if (IS_ERR(rdev)) { @@ -2166,9 +2150,6 @@ abort_export: static int set_array_info(mddev_t * mddev, mdu_array_info_t *info) { - if (alloc_array_sb(mddev)) - return -ENOMEM; - mddev->major_version = MD_MAJOR_VERSION; mddev->minor_version = MD_MINOR_VERSION; mddev->patch_version = MD_PATCHLEVEL_VERSION; @@ -2316,8 +2297,8 @@ static int md_ioctl(struct inode *inode, struct file *file, err = -EBUSY; goto abort_unlock; } - if (mddev->sb) { - printk(KERN_WARNING "md: array md%d already has a superblock!\n", + if (mddev->raid_disks) { + printk(KERN_WARNING "md: array md%d already initialised!\n", mdidx(mddev)); err = -EBUSY; goto abort_unlock; @@ -2342,8 +2323,8 @@ static int md_ioctl(struct inode *inode, struct file *file, /* * Commands querying/configuring an existing array: */ - /* if we don't have a superblock yet, only ADD_NEW_DISK or STOP_ARRAY is allowed */ - if (!mddev->sb && cmd != ADD_NEW_DISK && cmd != STOP_ARRAY && cmd != RUN_ARRAY) { + /* if we are initialised yet, only ADD_NEW_DISK or STOP_ARRAY is allowed */ + if (!mddev->raid_disks && cmd != ADD_NEW_DISK && cmd != STOP_ARRAY && cmd != RUN_ARRAY) { err = -ENODEV; goto abort_unlock; } @@ -3086,14 +3067,12 @@ static void md_do_sync(void *data) void md_do_recovery(void *data) { mddev_t *mddev; - mdp_super_t *sb; struct list_head *tmp; dprintk(KERN_INFO "md: recovery thread got woken up ...\n"); ITERATE_MDDEV(mddev,tmp) if (mddev_lock(mddev)==0) { - sb = mddev->sb; - if (!sb || !mddev->pers || mddev->ro) + if (!mddev->raid_disks || !mddev->pers || mddev->ro) goto unlock; if (mddev->sb_dirty) md_update_sb(mddev); @@ -3483,7 +3462,7 @@ void __init md_setup_drive(void) continue; } - if (mddev->sb || !list_empty(&mddev->disks)) { + if (mddev->raid_disks || !list_empty(&mddev->disks)) { printk(KERN_WARNING "md: Ignoring md=%d, already autodetected. (Use raid=noautodetect)\n", minor); diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h index f7da358ca006..0928a6c04c20 100644 --- a/include/linux/raid/md_k.h +++ b/include/linux/raid/md_k.h @@ -170,7 +170,6 @@ struct mddev_s void *private; mdk_personality_t *pers; int __minor; - mdp_super_t *sb; struct list_head disks; int sb_dirty; int ro; -- cgit v1.2.3 From 3ec593609c703bd8242dfde60bdb821bef5c1ff6 Mon Sep 17 00:00:00 2001 From: Neil Brown Date: Thu, 18 Jul 2002 19:12:13 -0700 Subject: [PATCH] MD - Get rid of dev in rdev and use bdev exclusively. Get rid of dev in rdev and use bdev exclusively. There is an awkwardness here in that userspace sometimes passed down a dev_t (e.g. hot_add_disk) and sometime a major and a minor (e.g. add_new_disk). Should we convert both to kdev_t as the uniform standard.... That is what was being done but it seemed very clumsy and things were gets converted back and forth a lot. As bdget used a dev_t, I felt safe in staying with dev_t once I had one rather than converting to kdev_t and back. --- drivers/md/md.c | 106 ++++++++++++++++++++++++++-------------------- include/linux/raid/md_k.h | 2 - 2 files changed, 59 insertions(+), 49 deletions(-) (limited to 'include/linux') diff --git a/drivers/md/md.c b/drivers/md/md.c index 4c28ed54ea63..549063948426 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -36,6 +36,7 @@ #include #include #include +#include /* for invalidate_bdev */ #include @@ -248,13 +249,25 @@ mdk_rdev_t * find_rdev_nr(mddev_t *mddev, int nr) return NULL; } -mdk_rdev_t * find_rdev(mddev_t * mddev, kdev_t dev) +static mdk_rdev_t * find_rdev(mddev_t * mddev, dev_t dev) { struct list_head *tmp; mdk_rdev_t *rdev; ITERATE_RDEV(mddev,rdev,tmp) { - if (kdev_same(rdev->dev, dev)) + if (rdev->bdev->bd_dev == dev) + return rdev; + } + return NULL; +} + +static mdk_rdev_t * find_rdev_bdev(mddev_t * mddev, struct block_device *bdev) +{ + struct list_head *tmp; + mdk_rdev_t *rdev; + + ITERATE_RDEV(mddev,rdev,tmp) { + if (rdev->bdev == bdev) return rdev; } return NULL; @@ -552,12 +565,12 @@ static void unbind_rdev_from_array(mdk_rdev_t * rdev) * inode is not enough, the SCSI module usage code needs * an explicit open() on the device] */ -static int lock_rdev(mdk_rdev_t *rdev) +static int lock_rdev(mdk_rdev_t *rdev, dev_t dev) { int err = 0; struct block_device *bdev; - bdev = bdget(kdev_t_to_nr(rdev->dev)); + bdev = bdget(dev); if (!bdev) return -ENOMEM; err = blkdev_get(bdev, FMODE_READ|FMODE_WRITE, 0, BDEV_RAW); @@ -582,7 +595,7 @@ static void unlock_rdev(mdk_rdev_t *rdev) blkdev_put(bdev, BDEV_RAW); } -void md_autodetect_dev(kdev_t dev); +void md_autodetect_dev(dev_t dev); static void export_rdev(mdk_rdev_t * rdev) { @@ -593,9 +606,8 @@ static void export_rdev(mdk_rdev_t * rdev) list_del_init(&rdev->same_set); unlock_rdev(rdev); #ifndef MODULE - md_autodetect_dev(rdev->dev); + md_autodetect_dev(rdev->bdev->bd_dev); #endif - rdev->dev = NODEV; rdev->faulty = 0; kfree(rdev); } @@ -869,8 +881,8 @@ static void sync_sbs(mddev_t * mddev) mdp_disk_t *d = &sb->disks[rdev->desc_nr]; nr_disks++; d->number = rdev->desc_nr; - d->major = major(rdev->dev); - d->minor = minor(rdev->dev); + d->major = MAJOR(rdev->bdev->bd_dev); + d->minor = MINOR(rdev->bdev->bd_dev); d->raid_disk = rdev->raid_disk; if (rdev->faulty) { d->state = (1<sb set. */ -static mdk_rdev_t *md_import_device(kdev_t newdev, int on_disk) +static mdk_rdev_t *md_import_device(dev_t newdev, int on_disk) { int err; mdk_rdev_t *rdev; @@ -992,7 +1004,7 @@ static mdk_rdev_t *md_import_device(kdev_t newdev, int on_disk) rdev = (mdk_rdev_t *) kmalloc(sizeof(*rdev), GFP_KERNEL); if (!rdev) { - printk(KERN_ERR "md: could not alloc mem for %s!\n", partition_name(newdev)); + printk(KERN_ERR "md: could not alloc mem for %s!\n", partition_name(to_kdev_t(newdev))); return ERR_PTR(-ENOMEM); } memset(rdev, 0, sizeof(*rdev)); @@ -1000,11 +1012,10 @@ static mdk_rdev_t *md_import_device(kdev_t newdev, int on_disk) if ((err = alloc_disk_sb(rdev))) goto abort_free; - rdev->dev = newdev; - err = lock_rdev(rdev); + err = lock_rdev(rdev, newdev); if (err) { printk(KERN_ERR "md: could not lock %s.\n", - partition_name(newdev)); + partition_name(to_kdev_t(newdev))); goto abort_free; } rdev->desc_nr = -1; @@ -1435,7 +1446,8 @@ static int do_md_run(mddev_t * mddev) ITERATE_RDEV(mddev,rdev,tmp) { if (rdev->faulty) continue; - invalidate_device(rdev->dev, 1); + sync_blockdev(rdev->bdev); + invalidate_bdev(rdev->bdev, 0); #if 0 /* * Aside of obvious breakage (code below results in block size set @@ -1745,7 +1757,7 @@ static void autorun_devices(void) #define AUTORUNNING KERN_INFO \ "md: auto-running md%d.\n" -static int autostart_array(kdev_t startdev) +static int autostart_array(dev_t startdev) { int err = -EINVAL, i; mdp_super_t *sb = NULL; @@ -1753,7 +1765,7 @@ static int autostart_array(kdev_t startdev) start_rdev = md_import_device(startdev, 1); if (IS_ERR(start_rdev)) { - printk(KERN_WARNING "md: could not import %s!\n", partition_name(startdev)); + printk(KERN_WARNING "md: could not import %s!\n", partition_name(to_kdev_t(startdev))); goto abort; } @@ -1776,19 +1788,19 @@ static int autostart_array(kdev_t startdev) for (i = 0; i < MD_SB_DISKS; i++) { mdp_disk_t *desc; - kdev_t dev; + dev_t dev; desc = sb->disks + i; - dev = mk_kdev(desc->major, desc->minor); + dev = MKDEV(desc->major, desc->minor); - if (kdev_none(dev)) + if (!dev) continue; - if (kdev_same(dev, startdev)) + if (dev == startdev) continue; rdev = md_import_device(dev, 1); if (IS_ERR(rdev)) { printk(KERN_WARNING "md: could not import %s, trying to run array nevertheless.\n", - partition_name(dev)); + partition_name(to_kdev_t(dev))); continue; } list_add(&rdev->same_set, &pending_raid_disks); @@ -1896,8 +1908,8 @@ static int get_disk_info(mddev_t * mddev, void * arg) rdev = find_rdev_nr(mddev, nr); if (rdev) { - info.major = major(rdev->dev); - info.minor = minor(rdev->dev); + info.major = MAJOR(rdev->bdev->bd_dev); + info.minor = MINOR(rdev->bdev->bd_dev); info.raid_disk = rdev->raid_disk; info.state = 0; if (rdev->faulty) @@ -1922,8 +1934,8 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info) { int size; mdk_rdev_t *rdev; - kdev_t dev; - dev = mk_kdev(info->major,info->minor); + dev_t dev; + dev = MKDEV(info->major,info->minor); if (!mddev->raid_disks) { /* expecting a device which has a superblock */ rdev = md_import_device(dev, 1); @@ -1980,7 +1992,7 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info) return 0; } -static int hot_generate_error(mddev_t * mddev, kdev_t dev) +static int hot_generate_error(mddev_t * mddev, dev_t dev) { struct request_queue *q; mdk_rdev_t *rdev; @@ -1989,7 +2001,7 @@ static int hot_generate_error(mddev_t * mddev, kdev_t dev) return -ENODEV; printk(KERN_INFO "md: trying to generate %s error in md%d ... \n", - partition_name(dev), mdidx(mddev)); + partition_name(to_kdev_t(dev)), mdidx(mddev)); rdev = find_rdev(mddev, dev); if (!rdev) { @@ -2015,7 +2027,7 @@ static int hot_generate_error(mddev_t * mddev, kdev_t dev) return 0; } -static int hot_remove_disk(mddev_t * mddev, kdev_t dev) +static int hot_remove_disk(mddev_t * mddev, dev_t dev) { int err; mdk_rdev_t *rdev; @@ -2024,7 +2036,7 @@ static int hot_remove_disk(mddev_t * mddev, kdev_t dev) return -ENODEV; printk(KERN_INFO "md: trying to remove %s from md%d ... \n", - partition_name(dev), mdidx(mddev)); + partition_name(to_kdev_t(dev)), mdidx(mddev)); if (!mddev->pers->hot_remove_disk) { printk(KERN_WARNING "md%d: personality does not support diskops!\n", @@ -2059,7 +2071,7 @@ busy: return -EBUSY; } -static int hot_add_disk(mddev_t * mddev, kdev_t dev) +static int hot_add_disk(mddev_t * mddev, dev_t dev) { int i, err; unsigned int size; @@ -2069,7 +2081,7 @@ static int hot_add_disk(mddev_t * mddev, kdev_t dev) return -ENODEV; printk(KERN_INFO "md: trying to hot-add %s to md%d ... \n", - partition_name(dev), mdidx(mddev)); + partition_name(to_kdev_t(dev)), mdidx(mddev)); if (!mddev->pers->hot_add_disk) { printk(KERN_WARNING "md%d: personality does not support diskops!\n", @@ -2176,7 +2188,7 @@ static int set_array_info(mddev_t * mddev, mdu_array_info_t *info) return 0; } -static int set_disk_faulty(mddev_t *mddev, kdev_t dev) +static int set_disk_faulty(mddev_t *mddev, dev_t dev) { mdk_rdev_t *rdev; int ret; @@ -2270,7 +2282,7 @@ static int md_ioctl(struct inode *inode, struct file *file, /* START_ARRAY doesn't need to lock the array as autostart_array * does the locking, and it could even be a different array */ - err = autostart_array(val_to_kdev(arg)); + err = autostart_array(arg); if (err) { printk(KERN_WARNING "md: autostart %s failed!\n", partition_name(val_to_kdev(arg))); @@ -2401,18 +2413,18 @@ static int md_ioctl(struct inode *inode, struct file *file, goto done_unlock; } case HOT_GENERATE_ERROR: - err = hot_generate_error(mddev, val_to_kdev(arg)); + err = hot_generate_error(mddev, arg); goto done_unlock; case HOT_REMOVE_DISK: - err = hot_remove_disk(mddev, val_to_kdev(arg)); + err = hot_remove_disk(mddev, arg); goto done_unlock; case HOT_ADD_DISK: - err = hot_add_disk(mddev, val_to_kdev(arg)); + err = hot_add_disk(mddev, arg); goto done_unlock; case SET_DISK_FAULTY: - err = set_disk_faulty(mddev, val_to_kdev(arg)); + err = set_disk_faulty(mddev, arg); goto done_unlock; case RUN_ARRAY: @@ -2626,10 +2638,9 @@ static void md_recover_arrays(void) int md_error(mddev_t *mddev, struct block_device *bdev) { mdk_rdev_t * rrdev; - kdev_t rdev = to_kdev_t(bdev->bd_dev); dprintk("md_error dev:(%d:%d), rdev:(%d:%d), (caller: %p,%p,%p,%p).\n", - MD_MAJOR,mdidx(mddev),major(rdev),minor(rdev), + MD_MAJOR,mdidx(mddev),MAJOR(bdev->bd_dev),MINOR(bdev->bd_dev), __builtin_return_address(0),__builtin_return_address(1), __builtin_return_address(2),__builtin_return_address(3)); @@ -2637,7 +2648,7 @@ int md_error(mddev_t *mddev, struct block_device *bdev) MD_BUG(); return 0; } - rrdev = find_rdev(mddev, rdev); + rrdev = find_rdev_bdev(mddev, bdev); if (!rrdev || rrdev->faulty) return 0; if (!mddev->pers->error_handler @@ -2861,8 +2872,9 @@ static int is_mddev_idle(mddev_t *mddev) idle = 1; ITERATE_RDEV(mddev,rdev,tmp) { - int major = major(rdev->dev); - int idx = disk_index(rdev->dev); + kdev_t dev = to_kdev_t(rdev->bdev->bd_dev); + int major = major(dev); + int idx = disk_index(dev); if ((idx >= DK_MAX_DISK) || (major >= DK_MAX_MAJOR)) continue; @@ -3273,10 +3285,10 @@ struct { * Searches all registered partitions for autorun RAID arrays * at boot time. */ -static kdev_t detected_devices[128]; +static dev_t detected_devices[128]; static int dev_cnt; -void md_autodetect_dev(kdev_t dev) +void md_autodetect_dev(dev_t dev) { if (dev_cnt >= 0 && dev_cnt < 127) detected_devices[dev_cnt++] = dev; @@ -3291,12 +3303,12 @@ static void autostart_arrays(void) printk(KERN_INFO "md: Autodetecting RAID arrays.\n"); for (i = 0; i < dev_cnt; i++) { - kdev_t dev = detected_devices[i]; + dev_t dev = detected_devices[i]; rdev = md_import_device(dev,1); if (IS_ERR(rdev)) { printk(KERN_ALERT "md: could not import %s!\n", - partition_name(dev)); + partition_name(to_kdev_t(dev))); continue; } if (rdev->faulty) { diff --git a/include/linux/raid/md_k.h b/include/linux/raid/md_k.h index 0928a6c04c20..12358bb23a99 100644 --- a/include/linux/raid/md_k.h +++ b/include/linux/raid/md_k.h @@ -144,7 +144,6 @@ struct mdk_rdev_s { struct list_head same_set; /* RAID devices within the same set */ - kdev_t dev; /* Device number */ unsigned long size; /* Device size (in blocks) */ mddev_t *mddev; /* RAID array if running */ unsigned long last_events; /* IO event timestamp */ @@ -249,7 +248,6 @@ static inline kdev_t mddev_to_kdev(mddev_t * mddev) return mk_kdev(MD_MAJOR, mdidx(mddev)); } -extern mdk_rdev_t * find_rdev(mddev_t * mddev, kdev_t dev); extern mdk_rdev_t * find_rdev_nr(mddev_t *mddev, int nr); extern mdk_rdev_t *get_spare(mddev_t *mddev); -- cgit v1.2.3 From e9356da889878f12ef8be47d291e78affbc71750 Mon Sep 17 00:00:00 2001 From: Martin Dalecki Date: Thu, 18 Jul 2002 19:26:04 -0700 Subject: [PATCH] 2.5.26 IDE 99 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most noticable in the patch: 1. we handle IRQ sharing now better then ever 2. survives quite a lot of testing by few people. Forexample cat /dev/hdb > /dev/null, where /dev/hdb contains a CD-ROM with a big cratch on the surface making sure it's broken :-). it's BTW. amanzing how wide the cratch had to be until errors ocurred. 3. Doesn't play with rq_rdev and friends Fri Jul 12 05:04:32 CEST 2002 ide-clean-99 - Push nIEN disabling down at the place where we are finished with a particular request. - First round of command line parser cleanups by Gerald Champagne. - Unfold the drive eviction functions in do_request(). This allowed us to realize that we don't have to re-get the major/minor numbers of the device we are action on from the raw device field of the currently running request. One significant place less in kernel where major/minor data gets manipulated. - Move the big IDE_BUSY loop out of do_request to do_ide_request(). This makes us realize that we don't have to clear the IDE_BUSY bit just before reentering do_request to look for more requests still pending on the queue and set it immediately again. This is fixing a tinny race on the code path from IRQ or timer function, where we had a tinny window between the clearing of the IDE_BUSY bit and reentering the request queue for completely unrelated requests to come in to our way. - Don't return any value in do_reset1(). It's always ATA_OP_CONTINUES. Split it up in to two functions one for disks (well in fact channels) and one for ATAPI devices. It turns out that they can be moved to the places where they are used to clarify the code flow. The only function remaining is do_reset_channel() now. - Duplicate code from ide_do_drive_code explicitely in ide_raw_taskfile(). Simplify ide_raw_taskfile() thereafter. Realize that ide_do_drive_cmd() is now only used by ATAPI devices. Move it therefore to atapi.c. - Do busy polling for ATAPI reset operations. This is much safer then the previous timer games played there. It simply doesn't make sense to give the bus up during such a subtile operation. We don't have to disable IRQs here as well, since we are already under the protection of the do_request mechanisms. (Well hopefully...) - Remove no longer used reset_poll() function. poll_timeout and friends are now used only in pdc4030 code. Those function where not called from IRQ context but they where set as handlers and not as expiry functions. - Return ATA_OP_CONTINUES instead of ATA_OP_FINISHED in ata_error(), to signal that we are willing to retry the operation until the maximal number of retry attempts is exceeded. Returning ATA_OP_FINISHED without prior end_request() hangs the system. - Apply trivia from DJ patch set. - Apply small configuration fix to ide-pci.c from Muli Ben-Yehuda. - Feed add_blkdev_randomness with information we already have in struct ata_channel *ch->major, instead of using the major(macro) on the request in question. - Make ide_raw_taskfile use the same request submission mechanism as tcq_invalidate_queue(). Something similar would be ideal for ioctl() code as well. - Implement actual device reset. Realize that the recalibration procedure is doomed by the standard. Don't try to recover by recalibrating devices therefore -just our retry mechanism should work in those cases. And suddenly the error handling code is IRQ safe. - Reinvent the ATA reset operation, since it is apparently needed. We still have to do the whole transfer timing reconfiguration there. - Move drive_is_ready(), which is in reality an attempt to check for IRQ requesters without clearing the IRQ line, over to the place where it belongs: device.c, which is the direct device access abstraction place. Rename it to ata_status_irq() to prevent global name space pollution. - Updates to the pdc202xxx host chip controller setup code by Bart³omiej ¯o³nierkiewicz: Forward port 2.4 patch by Hank Yang from Promise: - Add PDC20271 support - Disable LBA48 support on PDC20262 - Fix ATAPI UDMA port value - Add new quirk drive - Adjust timings for all drives when using ATA133 - Update pdc202xx_reset() waiting time - Mark TCQ as dangerous and add some bits about it to the help. - Add some missing exports. - Some small ide-scsi.c host allocation fixes by sullivan. --- drivers/ide/Config.help | 9 +- drivers/ide/Config.in | 2 +- drivers/ide/atapi.c | 61 +++ drivers/ide/device.c | 38 +- drivers/ide/gayle.c | 8 +- drivers/ide/hd.c | 21 +- drivers/ide/ide-cd.c | 12 +- drivers/ide/ide-disk.c | 31 +- drivers/ide/ide-floppy.c | 4 +- drivers/ide/ide-m8xx.c | 27 +- drivers/ide/ide-pci.c | 135 ++++--- drivers/ide/ide-tape.c | 3 +- drivers/ide/ide-taskfile.c | 153 +++----- drivers/ide/ide.c | 896 +++++++++++++++++++-------------------------- drivers/ide/main.c | 193 ++++------ drivers/ide/pcidma.c | 4 +- drivers/ide/pdc202xx.c | 317 +++++++++------- drivers/ide/pdc4030.c | 8 +- drivers/ide/pdcraid.c | 2 +- drivers/ide/probe.c | 27 +- drivers/ide/tcq.c | 3 +- drivers/ide/umc8672.c | 4 +- drivers/scsi/ide-scsi.c | 8 +- include/linux/atapi.h | 26 +- include/linux/ide.h | 62 ++-- include/linux/pci_ids.h | 1 + 26 files changed, 1006 insertions(+), 1049 deletions(-) (limited to 'include/linux') diff --git a/drivers/ide/Config.help b/drivers/ide/Config.help index b1eefd90f5c0..74668ed23673 100644 --- a/drivers/ide/Config.help +++ b/drivers/ide/Config.help @@ -708,7 +708,14 @@ CONFIG_BLK_DEV_IDE_TCQ Digital drives in the Expert series (by nature of really being IBM drives). - If you have such a drive, say Y here. + However, please, note that there are host chip controllers which will + not cooperate properly if TCQ is enabled. This may cause serious + data loss! + + Since enabling TCQ doesn't appear to have any noticeable performance + impact on Linux: [feel free to correct me if you wish too please] + + Generally say N here. CONFIG_BLK_DEV_IDE_TCQ_DEPTH Maximum size of commands to enable per-drive. Any value between 1 diff --git a/drivers/ide/Config.in b/drivers/ide/Config.in index 77ebacac5de2..f2c8fe680de1 100644 --- a/drivers/ide/Config.in +++ b/drivers/ide/Config.in @@ -34,7 +34,7 @@ if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then dep_bool ' Use PCI DMA by default when available' CONFIG_IDEDMA_PCI_AUTO $CONFIG_BLK_DEV_IDEDMA_PCI dep_bool ' Enable DMA only for disks ' CONFIG_IDEDMA_ONLYDISK $CONFIG_IDEDMA_PCI_AUTO define_bool CONFIG_BLK_DEV_IDEDMA $CONFIG_BLK_DEV_IDEDMA_PCI - dep_bool ' ATA tagged command queueing (EXPERIMENTAL)' CONFIG_BLK_DEV_IDE_TCQ $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL + dep_bool ' ATA tagged command queueing (DANGEROUS)' CONFIG_BLK_DEV_IDE_TCQ $CONFIG_BLK_DEV_IDEDMA_PCI $CONFIG_EXPERIMENTAL dep_bool ' TCQ on by default' CONFIG_BLK_DEV_IDE_TCQ_DEFAULT $CONFIG_BLK_DEV_IDE_TCQ if [ "$CONFIG_BLK_DEV_IDE_TCQ" != "n" ]; then int ' Default queue depth' CONFIG_BLK_DEV_IDE_TCQ_DEPTH 32 diff --git a/drivers/ide/atapi.c b/drivers/ide/atapi.c index 8f11dc822d28..fdcd3c92ec8f 100644 --- a/drivers/ide/atapi.c +++ b/drivers/ide/atapi.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -115,6 +116,66 @@ void atapi_write(struct ata_device *drive, u8 *buf, unsigned int n) outsw(IDE_DATA_REG, buf + (n & ~0x03), 1); } + +/* + * This function issues a special IDE device request onto the request queue. + * + * If action is ide_wait, then the rq is queued at the end of the request + * queue, and the function sleeps until it has been processed. This is for use + * when invoked from an ioctl handler. + * + * If action is ide_preempt, then the rq is queued at the head of the request + * queue, displacing the currently-being-processed request and this function + * returns immediately without waiting for the new rq to be completed. This is + * VERY DANGEROUS, and is intended for careful use by the ATAPI tape/cdrom + * driver code. + * + * If action is ide_end, then the rq is queued at the end of the request queue, + * and the function returns immediately without waiting for the new rq to be + * completed. This is again intended for careful use by the ATAPI tape/cdrom + * driver code. + */ +int ide_do_drive_cmd(struct ata_device *drive, struct request *rq, ide_action_t action) +{ + unsigned long flags; + struct ata_channel *ch = drive->channel; + unsigned int major = ch->major; + request_queue_t *q = &drive->queue; + struct list_head *queue_head = &q->queue_head; + DECLARE_COMPLETION(wait); + +#ifdef CONFIG_BLK_DEV_PDC4030 + if (ch->chipset == ide_pdc4030 && rq->buffer) + return -ENOSYS; /* special drive cmds not supported */ +#endif + rq->errors = 0; + rq->rq_status = RQ_ACTIVE; + rq->rq_dev = mk_kdev(major, (drive->select.b.unit) << PARTN_BITS); + if (action == ide_wait) + rq->waiting = &wait; + + spin_lock_irqsave(ch->lock, flags); + + if (action == ide_preempt) + drive->rq = NULL; + else if (!blk_queue_empty(&drive->queue)) + queue_head = queue_head->prev; /* ide_end and ide_wait */ + + __elv_add_request(q, rq, queue_head); + + do_ide_request(q); + + spin_unlock_irqrestore(ch->lock, flags); + + if (action == ide_wait) { + wait_for_completion(&wait); /* wait for it to be serviced */ + return rq->errors ? -EIO : 0; /* return -EIO if errors */ + } + + return 0; +} + +EXPORT_SYMBOL(ide_do_drive_cmd); EXPORT_SYMBOL(atapi_discard_data); EXPORT_SYMBOL(atapi_write_zeros); EXPORT_SYMBOL(atapi_init_pc); diff --git a/drivers/ide/device.c b/drivers/ide/device.c index cd457931a8e2..5cdf3f957094 100644 --- a/drivers/ide/device.c +++ b/drivers/ide/device.c @@ -79,6 +79,8 @@ void ata_mask(struct ata_device *drive) ch->maskproc(drive); } +EXPORT_SYMBOL(ata_mask); + /* * Check the state of the status register. */ @@ -93,6 +95,39 @@ int ata_status(struct ata_device *drive, u8 good, u8 bad) EXPORT_SYMBOL(ata_status); +/* + * This is used to check for the drive status on the IRQ handling code path. + */ +int ata_status_irq(struct ata_device *drive) +{ + if (test_bit(IDE_DMA, drive->channel->active)) + return udma_irq_status(drive); + + /* Need to guarantee 400ns since last command was issued? + */ +#ifdef CONFIG_IDEPCI_SHARE_IRQ + + /* + * We do a passive status test under shared PCI interrupts on cards + * that truly share the ATA side interrupt, but may also share an + * interrupt with another pci card/device. + */ + + if (drive->channel->io_ports[IDE_CONTROL_OFFSET]) + drive->status = IN_BYTE(drive->channel->io_ports[IDE_CONTROL_OFFSET]); + + else +#endif + ata_status(drive, 0, 0); /* Note: this may clear a pending IRQ! */ + + if (drive->status & BUSY_STAT) + return 0; /* drive busy: definitely not interrupting */ + else + return 1; /* drive ready: *might* be interrupting */ +} + +EXPORT_SYMBOL(ata_status_irq); + /* * Busy-wait for the drive status to be not "busy". Check then the status for * all of the "good" bits and none of the "bad" bits, and if all is okay it @@ -210,6 +245,8 @@ void ata_out_regfile(struct ata_device *drive, struct hd_drive_task_hdr *rf) OUT_BYTE(rf->high_cylinder, ch->io_ports[IDE_HCYL_OFFSET]); } +EXPORT_SYMBOL(ata_out_regfile); + /* * Input a complete register file. */ @@ -223,5 +260,4 @@ void ata_in_regfile(struct ata_device *drive, struct hd_drive_task_hdr *rf) rf->high_cylinder = IN_BYTE(ch->io_ports[IDE_HCYL_OFFSET]); } - MODULE_LICENSE("GPL"); diff --git a/drivers/ide/gayle.c b/drivers/ide/gayle.c index caf98d595c8c..abfab0e8e59e 100644 --- a/drivers/ide/gayle.c +++ b/drivers/ide/gayle.c @@ -106,9 +106,9 @@ static int gayle_ack_intr_a1200(struct ata_channel *hwif) return 1; } - /* - * Probe for a Gayle IDE interface (and optionally for an IDE doubler) - */ +/* + * Probe for a Gayle IDE interface (and optionally for an IDE doubler) + */ void __init gayle_init(void) { @@ -122,7 +122,7 @@ void __init gayle_init(void) for (i = 0; i < GAYLE_NUM_PROBE_HWIFS; i++) { ide_ioreg_t base, ctrlport, irqport; - ide_ack_intr_t *ack_intr; + int (*ack_intr)(struct ata_channel *); hw_regs_t hw; int index; unsigned long phys_base, res_start, res_n; diff --git a/drivers/ide/hd.c b/drivers/ide/hd.c index 7fd714eb9765..7a1663772b87 100644 --- a/drivers/ide/hd.c +++ b/drivers/ide/hd.c @@ -132,16 +132,16 @@ unsigned long last_req; unsigned long read_timer(void) { + extern spinlock_t i8253_lock; unsigned long t, flags; int i; - save_flags(flags); - cli(); + spin_lock_irqsave(&i8253_lock, flags); t = jiffies * 11932; outb_p(0, 0x43); i = inb_p(0x40); i |= inb(0x40) << 8; - restore_flags(flags); + spin_unlock_irqrestore(&i8253_lock, flags); return(t - i); } #endif @@ -817,8 +817,19 @@ static void __init hd_geninit(void) NR_HD = 0; return; } - request_region(HD_DATA, 8, "hd"); - request_region(HD_CMD, 1, "hd(cmd)"); + if (!request_region(HD_DATA, 8, "hd")) { + printk(KERN_WARNING "hd: port 0x%x busy\n", HD_DATA); + NR_HD = 0; + free_irq(HD_IRQ, NULL); + return; + } + if (!request_region(HD_CMD, 1, "hd(cmd)")) { + printk(KERN_WARNING "hd: port 0x%x busy\n", HD_CMD); + NR_HD = 0; + free_irq(HD_IRQ, NULL); + release_region(HD_DATA, 8); + return; + } hd_gendisk.nr_real = NR_HD; diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c index 4e9b658002c2..70917c42b27f 100644 --- a/drivers/ide/ide-cd.c +++ b/drivers/ide/ide-cd.c @@ -556,7 +556,7 @@ static void cdrom_end_request(struct ata_device *drive, struct request *rq, int if ((rq->flags & REQ_CMD) && !rq->current_nr_sectors) uptodate = 1; - __ata_end_request(drive, rq, uptodate, 0); + ata_end_request(drive, rq, uptodate, 0); } @@ -912,7 +912,7 @@ static ide_startstop_t cdrom_read_intr(struct ata_device *drive, struct request if (dma) { if (!dma_error) { - __ata_end_request(drive, rq, 1, rq->nr_sectors); + ata_end_request(drive, rq, 1, rq->nr_sectors); return ATA_OP_FINISHED; } else @@ -1497,7 +1497,7 @@ static ide_startstop_t cdrom_write_intr(struct ata_device *drive, struct request if (dma_error) return ata_error(drive, rq, "dma error"); - __ata_end_request(drive, rq, 1, rq->nr_sectors); + ata_end_request(drive, rq, 1, rq->nr_sectors); return ATA_OP_FINISHED; } @@ -1936,7 +1936,7 @@ static int cdrom_read_toc(struct ata_device *drive, struct request_sense *sense) If we get an error for the regular case, we assume a CDI without additional audio tracks. In this case the readable TOC is empty (CDI tracks are not included) - and only holds the Leadout entry. Heiko Eißfeldt */ + and only holds the Leadout entry. Heiko EiÃ^ßfeldt */ ntracks = 0; stat = cdrom_read_tocentry(drive, CDROM_LEADOUT, 1, 0, (char *)&toc->hdr, @@ -2840,11 +2840,11 @@ static int ide_cdrom_setup(struct ata_device *drive) } /* Forwarding functions to generic routines. */ -static int ide_cdrom_ioctl (struct ata_device *drive, +static int ide_cdrom_ioctl(struct ata_device *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - return cdrom_ioctl (inode, file, cmd, arg); + return cdrom_ioctl(inode, file, cmd, arg); } static int ide_cdrom_open (struct inode *ip, struct file *fp, struct ata_device *drive) diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c index cf9a29aa0e93..8ebd46f0e963 100644 --- a/drivers/ide/ide-disk.c +++ b/drivers/ide/ide-disk.c @@ -140,7 +140,7 @@ static ide_startstop_t task_in_intr(struct ata_device *drive, struct request *rq --rq->current_nr_sectors; if (rq->current_nr_sectors <= 0) { - if (!__ata_end_request(drive, rq, 1, 0)) { + if (!ata_end_request(drive, rq, 1, 0)) { // printk("Request Ended stat: %02x\n", drive->status); return ATA_OP_FINISHED; @@ -166,7 +166,7 @@ static ide_startstop_t task_out_intr(struct ata_device *drive, struct request *r if (!ata_status(drive, DRIVE_READY, drive->bad_wstat)) return ata_error(drive, rq, __FUNCTION__); - if (!rq->current_nr_sectors && !__ata_end_request(drive, rq, 1, 0)) { + if (!rq->current_nr_sectors && !ata_end_request(drive, rq, 1, 0)) { ret = ATA_OP_FINISHED; } else { if ((rq->nr_sectors == 1) != (drive->status & DRQ_STAT)) { @@ -235,7 +235,7 @@ static ide_startstop_t task_mulin_intr(struct ata_device *drive, struct request /* FIXME: this seems buggy */ if (rq->current_nr_sectors <= 0) { - if (!__ata_end_request(drive, rq, 1, 0)) + if (!ata_end_request(drive, rq, 1, 0)) return ATA_OP_FINISHED; } msect -= nsect; @@ -269,7 +269,7 @@ static ide_startstop_t task_mulout_intr(struct ata_device *drive, struct request return ata_error(drive, rq, __FUNCTION__); } if (!rq->nr_sectors) { - __ata_end_request(drive, rq, 1, rq->hard_nr_sectors); + ata_end_request(drive, rq, 1, rq->hard_nr_sectors); rq->bio = NULL; ret = ATA_OP_FINISHED; } else if (!ok) { @@ -349,7 +349,7 @@ static ide_startstop_t idedisk_do_request(struct ata_device *drive, struct reque /* FIXME: this check doesn't make sense */ if (!(rq->flags & REQ_CMD)) { blk_dump_rq_flags(rq, "idedisk_do_request - bad command"); - __ata_end_request(drive, rq, 0, 0); + ata_end_request(drive, rq, 0, 0); return ATA_OP_FINISHED; } @@ -514,8 +514,8 @@ static ide_startstop_t idedisk_do_request(struct ata_device *drive, struct reque printk("sectors=%ld, ", rq->nr_sectors); printk("buffer=%p\n", rq->buffer); #endif - ar->cmd = cmd; - rq->special = ar; + ar->cmd = cmd; + rq->special = ar; } /* (ks/hs): Moved to start, do not use for multiple out commands. @@ -548,10 +548,9 @@ static ide_startstop_t idedisk_do_request(struct ata_device *drive, struct reque return ATA_OP_CONTINUES; } - /* FIXME: Warning check for race between handler and prehandler - * for writing first block of data. however since we are well - * inside the boundaries of the seek, we should be okay. - * FIXME: should be fixed --bzolnier + /* FIXME: Warning check for race between handlers for writing + * first block of data. However since we are well inside the + * boundaries of the seek, we should be okay. */ if (ar->command_type == IDE_DRIVE_TASK_RAW_WRITE) { ide_startstop_t ret; @@ -596,13 +595,15 @@ static ide_startstop_t idedisk_do_request(struct ata_device *drive, struct reque * * FIXME: Replace hard-coded 100, what about * error handling? + * + * FIXME: Whatabout the IRE clearing and not clearing case?! */ for (i = 0; i < 100; ++i) { - if (drive_is_ready(drive)) + if (ata_status_irq(drive)) break; } - if (!drive_is_ready(drive)) { + if (!ata_status_irq(drive)) { /* We are compleatly missing an error * return path here. * FIXME: We have only one? -alat @@ -1290,7 +1291,9 @@ static int idedisk_cleanup(struct ata_device *drive) return ret; } -static int idedisk_ioctl(struct ata_device *drive, struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +static int idedisk_ioctl(struct ata_device *drive, + struct inode *inode, struct file *__fp, + unsigned int cmd, unsigned long arg) { struct hd_driveid *id = drive->id; diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c index 83cb749e243f..9dca9511a417 100644 --- a/drivers/ide/ide-floppy.c +++ b/drivers/ide/ide-floppy.c @@ -96,6 +96,7 @@ #include #include #include +#include #include #include @@ -367,7 +368,7 @@ static int idefloppy_end_request(struct ata_device *drive, struct request *rq, i return 0; if (!(rq->flags & REQ_SPECIAL)) { - __ata_end_request(drive, rq, uptodate, 0); + ata_end_request(drive, rq, uptodate, 0); return 0; } @@ -731,7 +732,6 @@ static ide_startstop_t idefloppy_transfer_pc2(struct ata_device *drive, struct r static ide_startstop_t idefloppy_transfer_pc1(struct ata_device *drive, struct request *rq) { idefloppy_floppy_t *floppy = drive->driver_data; - ide_startstop_t startstop; atapi_ireason_reg_t ireason; int ret; diff --git a/drivers/ide/ide-m8xx.c b/drivers/ide/ide-m8xx.c index ce50d7fa49f3..a04398c9e12c 100644 --- a/drivers/ide/ide-m8xx.c +++ b/drivers/ide/ide-m8xx.c @@ -50,7 +50,7 @@ static void print_fixed (volatile unsigned char *p); static void print_funcid (int func); static int check_ide_device (unsigned long base); -static void ide_interrupt_ack (void *dev); +static int ide_interrupt_ack(struct ata_channel *); static void m8xx_ide_tuneproc(struct ata_device *drive, byte pio); typedef struct ide_ioport_desc { @@ -326,7 +326,7 @@ m8xx_ide_init_hwif_ports(hw_regs_t *hw, ide_ioreg_t data_port, /* register routine to tune PIO mode */ ide_hwifs[data_port].tuneproc = m8xx_ide_tuneproc; - hw->ack_intr = (ide_ack_intr_t *) ide_interrupt_ack; + hw->ack_intr = ide_interrupt_ack; /* Enable Harddisk Interrupt, * and make it edge sensitive */ @@ -401,7 +401,7 @@ void m8xx_ide_init_hwif_ports (hw_regs_t *hw, ioport_dsc[data_port].reg_off[i], i, base + ioport_dsc[data_port].reg_off[i]); #endif - *p++ = base + ioport_dsc[data_port].reg_off[i]; + *p++ = base + ioport_dsc[data_port].reg_off[i]; } if (irq) { @@ -412,16 +412,16 @@ void m8xx_ide_init_hwif_ports (hw_regs_t *hw, /* register routine to tune PIO mode */ ide_hwifs[data_port].tuneproc = m8xx_ide_tuneproc; - hw->ack_intr = (ide_ack_intr_t *) ide_interrupt_ack; + hw->ack_intr = ide_interrupt_ack; /* Enable Harddisk Interrupt, * and make it edge sensitive */ /* (11-18) Set edge detect for irq, no wakeup from low power mode */ ((immap_t *) IMAP_ADDR)->im_siu_conf.sc_siel |= (0x80000000 >> ioport_dsc[data_port].irq); -} /* m8xx_ide_init_hwif_ports() for CONFIG_IDE_8xx_DIRECT */ +} /* m8xx_ide_init_hwif_ports() for CONFIG_IDE_8xx_DIRECT */ -#endif /* CONFIG_IDE_8xx_DIRECT */ +#endif /* -------------------------------------------------------------------- */ @@ -493,11 +493,10 @@ m8xx_ide_tuneproc(struct ata_device *drive, byte pio) printk("%s[%d] %s: not implemented yet!\n", __FILE__,__LINE__,__FUNCTION__); -#endif /* defined(CONFIG_IDE_8xx_PCCARD) || defined(CONFIG_IDE_8xx_PCMCIA */ +#endif } -static void -ide_interrupt_ack (void *dev) +static int ide_interrupt_ack(struct ata_channel *ch) { #ifdef CONFIG_IDE_8xx_PCCARD u_int pscr, pipr; @@ -529,17 +528,17 @@ ide_interrupt_ack (void *dev) /* clear the interrupt sources */ ((immap_t *)IMAP_ADDR)->im_pcmcia.pcmc_pscr = pscr; -#else /* ! CONFIG_IDE_8xx_PCCARD */ +#else /* * Only CONFIG_IDE_8xx_PCCARD is using the interrupt of the * MPC8xx's PCMCIA controller, so there is nothing to be done here * for CONFIG_IDE_8xx_DIRECT and CONFIG_IDE_EXT_DIRECT. * The interrupt is handled somewhere else. -- Steven */ -#endif /* CONFIG_IDE_8xx_PCCARD */ -} - +#endif + return 0; +} /* * CIS Tupel codes @@ -655,7 +654,7 @@ static int check_ide_device (unsigned long base) q+= 2; } } -#endif /* DEBUG_PCMCIA */ +#endif switch (code) { case CISTPL_VERS_1: ident = p + 4; diff --git a/drivers/ide/ide-pci.c b/drivers/ide/ide-pci.c index 0b6fe40cd806..fc6ccc4f6a8f 100644 --- a/drivers/ide/ide-pci.c +++ b/drivers/ide/ide-pci.c @@ -158,6 +158,80 @@ static int __init setup_pci_baseregs(struct pci_dev *dev, const char *name) return 0; } +#ifdef CONFIG_BLK_DEV_IDEDMA +/* + * Setup DMA transfers on the channel. + */ +static void __init setup_channel_dma(struct pci_dev *dev, + struct ata_pci_device* d, + int autodma, + struct ata_channel *ch) +{ + unsigned long dma_base; + + if (d->flags & ATA_F_NOADMA) + autodma = 0; + + if (autodma) + ch->autodma = 1; + + if (!((d->flags & ATA_F_DMA) || ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 0x80)))) + return; + + /* + * Fetch the DMA Bus-Master-I/O-Base-Address (BMIBA) from PCI space: + */ + dma_base = pci_resource_start(dev, 4); + if (dma_base) { + /* PDC20246, PDC20262, HPT343, & HPT366 */ + if ((ch->unit == ATA_PRIMARY) && d->extra) { + request_region(dma_base + 16, d->extra, dev->name); + ch->dma_extra = d->extra; + } + + /* If we are on the second channel, the dma base address will + * be one entry away from the primary interface. + */ + if (ch->unit == ATA_SECONDARY) + dma_base += 8; + + if (d->flags & ATA_F_SIMPLEX) { + outb(inb(dma_base + 2) & 0x60, dma_base + 2); + if (inb(dma_base + 2) & 0x80) + printk(KERN_INFO "%s: simplex device: DMA forced\n", dev->name); + } else { + /* If the device claims "simplex" DMA, this means only + * one of the two interfaces can be trusted with DMA at + * any point in time. So we should enable DMA only on + * one of the two interfaces. + */ + if ((inb(dma_base + 2) & 0x80)) { + if ((!ch->drives[0].present && !ch->drives[1].present) || + ch->unit == ATA_SECONDARY) { + printk(KERN_INFO "%s: simplex device: DMA disabled\n", dev->name); + dma_base = 0; + } + } + } + } else { + printk(KERN_INFO "%s: %s Bus-Master DMA was disabled by BIOS\n", + ch->name, dev->name); + + return; + } + + /* The function below will check itself whatever there is something to + * be done or not. We don't have therefore to care whatever it was + * already enabled by the primary channel run. + */ + pci_set_master(dev); + if (d->init_dma) + d->init_dma(ch, dma_base); + else + ata_init_dma(ch, dma_base); +} +#endif + /* * Setup a particular port on an ATA host controller. * @@ -171,7 +245,6 @@ static int __init setup_host_channel(struct pci_dev *dev, int autodma) { unsigned long base = 0; - unsigned long dma_base; unsigned long ctl = 0; ide_pci_enablebit_t *e = &(d->enablebits[port]); struct ata_channel *ch; @@ -260,69 +333,13 @@ controller_ok: if (ch->udma_four) printk("%s: warning: ATA-66/100 forced bit set!\n", dev->name); + #ifdef CONFIG_BLK_DEV_IDEDMA /* * Setup DMA transfers on the channel. */ - if (!((d->flags & ATA_F_DMA) || ((dev->class >> 8) == PCI_CLASS_STORAGE_IDE && (dev->class & 0x80)))) - goto no_dma; - /* - * Fetch the DMA Bus-Master-I/O-Base-Address (BMIBA) from PCI space: - */ - dma_base = pci_resource_start(dev, 4); - if (dma_base) { - /* PDC20246, PDC20262, HPT343, & HPT366 */ - if ((ch->unit == ATA_PRIMARY) && d->extra) { - request_region(dma_base + 16, d->extra, dev->name); - ch->dma_extra = d->extra; - } - - /* If we are on the second channel, the dma base address will - * be one entry away from the primary interface. - */ - if (ch->unit == ATA_SECONDARY) - dma_base += 8; - - if (d->flags & ATA_F_SIMPLEX) { - outb(inb(dma_base + 2) & 0x60, dma_base + 2); - if (inb(dma_base + 2) & 0x80) - printk(KERN_INFO "%s: simplex device: DMA forced\n", dev->name); - } else { - /* If the device claims "simplex" DMA, this means only - * one of the two interfaces can be trusted with DMA at - * any point in time. So we should enable DMA only on - * one of the two interfaces. - */ - if ((inb(dma_base + 2) & 0x80)) { - if ((!ch->drives[0].present && !ch->drives[1].present) || - ch->unit == ATA_SECONDARY) { - printk(KERN_INFO "%s: simplex device: DMA disabled\n", dev->name); - dma_base = 0; - } - } - } - } else { - printk(KERN_INFO "%s: %s Bus-Master DMA was disabled by BIOS\n", - ch->name, dev->name); - - goto no_dma; - } - - /* The function below will check itself whatever there is something to - * be done or not. We don't have therefore to care whatever it was - * already enabled by the primary channel run. - */ - pci_set_master(dev); - - if (autodma) - ch->autodma = 1; - - if (d->init_dma) - d->init_dma(ch, dma_base); - else - ata_init_dma(ch, dma_base); + setup_channel_dma(dev, d, autodma, ch); #endif - no_dma: /* Call chipset-specific routine for each enabled channel. */ if (d->init_channel) diff --git a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c index 36b8fa16ab52..70e052d6097d 100644 --- a/drivers/ide/ide-tape.c +++ b/drivers/ide/ide-tape.c @@ -421,6 +421,7 @@ #include #include #include +#include #include #include @@ -2445,7 +2446,7 @@ static ide_startstop_t idetape_do_request(struct ata_device *drive, struct reque * We do not support buffer cache originated requests. */ printk (KERN_NOTICE "ide-tape: %s: Unsupported command in request queue (%ld)\n", drive->name, rq->flags); - __ata_end_request(drive, rq, 0, 0); /* Let the common code handle it */ + ata_end_request(drive, rq, 0, 0); /* Let the common code handle it */ return ATA_OP_FINISHED; } diff --git a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c index 3d6bc592766e..2699a3f5de9a 100644 --- a/drivers/ide/ide-taskfile.c +++ b/drivers/ide/ide-taskfile.c @@ -33,18 +33,9 @@ #include #include -#define DEBUG_TASKFILE 0 /* unset when fixed */ - -#if DEBUG_TASKFILE -#define DTF(x...) printk(##x) -#else -#define DTF(x...) -#endif - /* * Data transfer functions for polled IO. */ - static void ata_read_32(struct ata_device *drive, void *buffer, unsigned int wcount) { insl(IDE_DATA_REG, buffer, wcount); @@ -143,103 +134,10 @@ void ata_write(struct ata_device *drive, void *buffer, unsigned int wcount) } } -/* - * Needed for PCI irq sharing - */ -int drive_is_ready(struct ata_device *drive) -{ - if (test_bit(IDE_DMA, drive->channel->active)) - return udma_irq_status(drive); - - /* - * Need to guarantee 400ns since last command was issued? - */ - - /* FIXME: promote this to the general status read method perhaps. - */ -#ifdef CONFIG_IDEPCI_SHARE_IRQ - /* - * We do a passive status test under shared PCI interrupts on - * cards that truly share the ATA side interrupt, but may also share - * an interrupt with another pci card/device. We make no assumptions - * about possible isa-pnp and pci-pnp issues yet. - */ - if (drive->channel->io_ports[IDE_CONTROL_OFFSET]) - drive->status = GET_ALTSTAT(); - else -#endif - ata_status(drive, 0, 0); /* Note: this may clear a pending IRQ! */ - - if (drive->status & BUSY_STAT) - return 0; /* drive busy: definitely not interrupting */ - - return 1; /* drive ready: *might* be interrupting */ -} - -/* - * This function issues a special IDE device request onto the request queue. - * - * If action is ide_wait, then the rq is queued at the end of the request - * queue, and the function sleeps until it has been processed. This is for use - * when invoked from an ioctl handler. - * - * If action is ide_preempt, then the rq is queued at the head of the request - * queue, displacing the currently-being-processed request and this function - * returns immediately without waiting for the new rq to be completed. This is - * VERY DANGEROUS, and is intended for careful use by the ATAPI tape/cdrom - * driver code. - * - * If action is ide_end, then the rq is queued at the end of the request queue, - * and the function returns immediately without waiting for the new rq to be - * completed. This is again intended for careful use by the ATAPI tape/cdrom - * driver code. - */ -int ide_do_drive_cmd(struct ata_device *drive, struct request *rq, ide_action_t action) -{ - unsigned long flags; - struct ata_channel *ch = drive->channel; - unsigned int major = ch->major; - request_queue_t *q = &drive->queue; - struct list_head *queue_head = &q->queue_head; - DECLARE_COMPLETION(wait); - -#ifdef CONFIG_BLK_DEV_PDC4030 - if (ch->chipset == ide_pdc4030 && rq->buffer) - return -ENOSYS; /* special drive cmds not supported */ -#endif - rq->errors = 0; - rq->rq_status = RQ_ACTIVE; - rq->rq_dev = mk_kdev(major,(drive->select.b.unit)<waiting = &wait; - - spin_lock_irqsave(ch->lock, flags); - - if (action == ide_preempt) - drive->rq = NULL; - else if (!blk_queue_empty(&drive->queue)) - queue_head = queue_head->prev; /* ide_end and ide_wait */ - - __elv_add_request(q, rq, queue_head); - - do_ide_request(q); - - spin_unlock_irqrestore(ch->lock, flags); - - if (action == ide_wait) { - wait_for_completion(&wait); /* wait for it to be serviced */ - return rq->errors ? -EIO : 0; /* return -EIO if errors */ - } - - return 0; -} - - /* * Invoked on completion of a special REQ_SPECIAL command. */ -static ide_startstop_t special_intr(struct ata_device *drive, struct - request *rq) { +static ide_startstop_t special_intr(struct ata_device *drive, struct request *rq) { unsigned long flags; struct ata_channel *ch =drive->channel; struct ata_taskfile *ar = rq->special; @@ -290,21 +188,52 @@ static ide_startstop_t special_intr(struct ata_device *drive, struct int ide_raw_taskfile(struct ata_device *drive, struct ata_taskfile *ar, char *buf) { - struct request req; + struct request *rq; + unsigned long flags; + struct ata_channel *ch = drive->channel; + request_queue_t *q = &drive->queue; + struct list_head *queue_head = &q->queue_head; + DECLARE_COMPLETION(wait); + +#ifdef CONFIG_BLK_DEV_PDC4030 + if (ch->chipset == ide_pdc4030 && buf) + return -ENOSYS; /* special drive cmds not supported */ +#endif + + rq = __blk_get_request(&drive->queue, READ); + if (!rq) + rq = __blk_get_request(&drive->queue, WRITE); + + /* + * FIXME: Make sure there is a free slot on the list! + */ + + BUG_ON(!rq); + + rq->flags = REQ_SPECIAL; + rq->buffer = buf; + rq->special = ar; + rq->errors = 0; + rq->rq_status = RQ_ACTIVE; + rq->waiting = &wait; - ar->command_type = IDE_DRIVE_TASK_NO_DATA; ar->XXX_handler = special_intr; + ar->command_type = IDE_DRIVE_TASK_NO_DATA; + + spin_lock_irqsave(ch->lock, flags); + + if (!blk_queue_empty(&drive->queue)) + queue_head = queue_head->prev; + __elv_add_request(q, rq, queue_head); + + q->request_fn(q); + spin_unlock_irqrestore(ch->lock, flags); - memset(&req, 0, sizeof(req)); - req.flags = REQ_SPECIAL; - req.buffer = buf; - req.special = ar; + wait_for_completion(&wait); /* wait for it to be serviced */ - return ide_do_drive_cmd(drive, &req, ide_wait); + return rq->errors ? -EIO : 0; /* return -EIO if errors */ } -EXPORT_SYMBOL(drive_is_ready); -EXPORT_SYMBOL(ide_do_drive_cmd); EXPORT_SYMBOL(ata_read); EXPORT_SYMBOL(ata_write); EXPORT_SYMBOL(ide_raw_taskfile); diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c index d1e6c8030f07..851ac69d6a8d 100644 --- a/drivers/ide/ide.c +++ b/drivers/ide/ide.c @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include @@ -106,7 +105,7 @@ int drive_is_flashcard(struct ata_device *drive) return 0; } -int __ata_end_request(struct ata_device *drive, struct request *rq, int uptodate, unsigned int nr_secs) +int ata_end_request(struct ata_device *drive, struct request *rq, int uptodate, unsigned int nr_secs) { unsigned long flags; struct ata_channel *ch = drive->channel; @@ -132,7 +131,7 @@ int __ata_end_request(struct ata_device *drive, struct request *rq, int uptodate } if (!end_that_request_first(rq, uptodate, nr_secs)) { - add_blkdev_randomness(major(rq->rq_dev)); + add_blkdev_randomness(ch->major); if (!blk_rq_tagged(rq)) blkdev_dequeue_request(rq); else @@ -192,12 +191,13 @@ static void check_crc_errors(struct ata_device *drive) if (mode > XFER_UDMA_0) mode--; else + /* - * OOPS we do not goto non Ultra DMA modes - * without iCRC's available we force - * the system to PIO and make the user - * invoke the ATA-1 ATA-2 DMA modes. + * We do not do non Ultra DMA modes. Without iCRC's + * available, we force the system to PIO and make the + * user select the ATA-1 ATA-2 DMA modes himself. */ + mode = XFER_PIO_4; drive->channel->speedproc(drive, mode); @@ -220,157 +220,9 @@ sector_t ata_capacity(struct ata_device *drive) if (ata_ops(drive) && ata_ops(drive)->capacity) return ata_ops(drive)->capacity(drive); - /* This used to be 0x7fffffff, but since now we use the maximal drive - * capacity value used by other kernel subsystems as well. - */ - return ~0UL; } -extern struct block_device_operations ide_fops[]; - -static ide_startstop_t do_reset1(struct ata_device *, int); /* needed below */ - -/* - * Poll the interface for completion every 50ms during an ATAPI drive reset - * operation. If the drive has not yet responded, and we have not yet hit our - * maximum waiting time, then the timer is restarted for another 50ms. - */ -static ide_startstop_t atapi_reset_pollfunc(struct ata_device *drive, struct request *__rq) -{ - struct ata_channel *ch = drive->channel; - int ret = ATA_OP_FINISHED; - - ata_select(drive, 10); - if (!ata_status(drive, 0, BUSY_STAT)) { - if (time_before(jiffies, ch->poll_timeout)) { - ata_set_handler(drive, atapi_reset_pollfunc, HZ/20, NULL); - ret = ATA_OP_CONTINUES; /* continue polling */ - } else { - ch->poll_timeout = 0; /* end of polling */ - printk("%s: ATAPI reset timed out, status=0x%02x\n", drive->name, drive->status); - - ret = do_reset1(drive, 0); /* do it the old fashioned way */ - } - } else { - printk("%s: ATAPI reset complete\n", drive->name); - ch->poll_timeout = 0; /* done polling */ - - ret = ATA_OP_FINISHED; - } - - return ret; -} - -/* - * Poll the interface for completion every 50ms during an ata reset operation. - * If the drives have not yet responded, and we have not yet hit our maximum - * waiting time, then the timer is restarted for another 50ms. - */ -static ide_startstop_t reset_pollfunc(struct ata_device *drive, struct request *__rq) -{ - struct ata_channel *ch = drive->channel; - int ret; - - if (!ata_status(drive, 0, BUSY_STAT)) { - if (time_before(jiffies, ch->poll_timeout)) { - ata_set_handler(drive, reset_pollfunc, HZ/20, NULL); - ret = ATA_OP_CONTINUES; /* continue polling */ - } else { - ch->poll_timeout = 0; /* done polling */ - printk("%s: reset timed out, status=0x%02x\n", ch->name, drive->status); - ++drive->failures; - ret = ATA_OP_FINISHED; - } - } else { - u8 stat; - - ch->poll_timeout = 0; /* done polling */ - printk("%s: reset: ", ch->name); - if ((stat = GET_ERR()) == 1) { - printk("success\n"); - drive->failures = 0; - } else { - const char *msg = ""; - -#if FANCY_STATUS_DUMPS - u8 val; - static const char *messages[5] = { - " passed", - " formatter device", - " sector buffer", - " ECC circuitry", - " controlling MPU error" - }; - - printk("master:"); - val = stat & 0x7f; - if (val >= 1 && val <= 5) - msg = messages[val -1]; - if (stat & 0x80) - printk("; slave:"); -#endif - printk(KERN_ERR "%s error [%02x]\n", msg, stat); - ++drive->failures; - } - - ret = ATA_OP_FINISHED; - } - - return ret; -} - -/* - * Attempt to recover a confused drive by resetting it. Unfortunately, - * resetting a disk drive actually resets all devices on the same interface, so - * it can really be thought of as resetting the interface rather than resetting - * the drive. - * - * ATAPI devices have their own reset mechanism which allows them to be - * individually reset without clobbering other devices on the same interface. - * - * Unfortunately, the IDE interface does not generate an interrupt to let us - * know when the reset operation has finished, so we must poll for this. - * Equally poor, though, is the fact that this may a very long time to - * complete, (up to 30 seconds worst case). So, instead of busy-waiting here - * for it, we set a timer to poll at 50ms intervals. - */ -static ide_startstop_t do_reset1(struct ata_device *drive, int try_atapi) -{ - unsigned int unit; - unsigned long flags; - struct ata_channel *ch = drive->channel; - - /* FIXME: --bzolnier */ - __save_flags(flags); /* local CPU only */ - __cli(); /* local CPU only */ - - /* For an ATAPI device, first try an ATAPI SRST. */ - if (try_atapi) { - if (drive->type != ATA_DISK) { - check_crc_errors(drive); - ata_select(drive, 20); - OUT_BYTE(WIN_SRST, IDE_COMMAND_REG); - ch->poll_timeout = jiffies + WAIT_WORSTCASE; - ata_set_handler(drive, atapi_reset_pollfunc, HZ/20, NULL); - __restore_flags(flags); /* local CPU only */ - - return ATA_OP_CONTINUES; - } - } - - /* - * First, reset any device state data we were maintaining - * for any of the drives on this interface. - */ - for (unit = 0; unit < MAX_DRIVES; ++unit) - check_crc_errors(&ch->drives[unit]); - - __restore_flags(flags); /* local CPU only */ - - return ATA_OP_CONTINUES; -} - static inline u32 read_24(struct ata_device *drive) { return (IN_BYTE(IDE_HCYL_REG) << 16) | @@ -489,58 +341,11 @@ u8 ata_dump(struct ata_device *drive, struct request * rq, const char *msg) return err; } -/* - * This gets invoked in response to a drive unexpectedly having its DRQ_STAT - * bit set. As an alternative to resetting the drive, it tries to clear the - * condition by reading a sector's worth of data from the drive. Of course, - * this may not help if the drive is *waiting* for data from *us*. - */ -static void try_to_flush_leftover_data(struct ata_device *drive) -{ - int i; - - if (drive->type != ATA_DISK) - return; - - for (i = (drive->mult_count ? drive->mult_count : 1); i > 0; --i) { - u32 buffer[SECTOR_WORDS]; - - ata_read(drive, buffer, SECTOR_WORDS); - } -} - -#ifdef CONFIG_BLK_DEV_PDC4030 -# define IS_PDC4030_DRIVE (drive->channel->chipset == ide_pdc4030) -#else -# define IS_PDC4030_DRIVE (0) /* auto-NULLs out pdc4030 code */ -#endif - -/* - * We are still on the old request path here so issuing the recalibrate command - * directly should just work. - */ -static int do_recalibrate(struct ata_device *drive) -{ - - if (drive->type != ATA_DISK) - return ATA_OP_FINISHED; - - if (!IS_PDC4030_DRIVE) { - struct ata_taskfile args; - - printk(KERN_INFO "%s: recalibrating...\n", drive->name); - memset(&args, 0, sizeof(args)); - args.taskfile.sector_count = drive->sect; - args.cmd = WIN_RESTORE; - ide_raw_taskfile(drive, &args, NULL); - printk(KERN_INFO "%s: done!\n", drive->name); - } - - return IS_PDC4030_DRIVE ? ATA_OP_FINISHED : ATA_OP_CONTINUES; -} - /* * Take action based on the error returned by the drive. + * + * FIXME: Separate the error handling code out and call it only in cases where + * we really wan't to try to recover from the error and not just reporting. */ ide_startstop_t ata_error(struct ata_device *drive, struct request *rq, const char *msg) { @@ -549,12 +354,9 @@ ide_startstop_t ata_error(struct ata_device *drive, struct request *rq, const ch err = ata_dump(drive, rq, msg); - /* FIXME: at least !drive check is bogus --bzolnier */ - if (!drive || !rq) - return ATA_OP_FINISHED; - - /* retry only "normal" I/O: */ - if (!(rq->flags & REQ_CMD)) { + /* Only try to recover from block I/O operations. + */ + if (!rq || !(rq->flags & REQ_CMD)) { rq->errors = 1; return ATA_OP_FINISHED; @@ -562,10 +364,11 @@ ide_startstop_t ata_error(struct ata_device *drive, struct request *rq, const ch /* other bits are useless when BUSY */ if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) - rq->errors |= ERROR_RESET; /* FIXME: What's that?! */ - else { - if (drive->type == ATA_DISK && (stat & ERR_STAT)) { - /* err has different meaning on cdrom and tape */ + rq->errors |= ERROR_RESET; + else if (drive->type == ATA_DISK) { + /* The error bit has different meaning on cdrom and tape. + */ + if (stat & ERR_STAT) { if (err == ABRT_ERR) { if (drive->select.b.lba && IN_BYTE(IDE_COMMAND_REG) == WIN_SPECIFY) return ATA_OP_FINISHED; /* some newer drives don't support WIN_SPECIFY */ @@ -573,109 +376,128 @@ ide_startstop_t ata_error(struct ata_device *drive, struct request *rq, const ch drive->crc_count++; /* UDMA crc error -- just retry the operation */ else if (err & (BBD_ERR | ECC_ERR)) /* retries won't help these */ rq->errors = ERROR_MAX; - else if (err & TRK0_ERR) /* help it find track zero */ - rq->errors |= ERROR_RECAL; } - /* pre bio (rq->cmd != WRITE) */ - if ((stat & DRQ_STAT) && rq_data_dir(rq) == READ) - try_to_flush_leftover_data(drive); + + /* As an alternative to resetting the drive, we try to clear + * the condition by reading a sector's worth of data from the + * drive. Of course, this can not help if the drive is + * *waiting* for data from *us*. + */ + + if ((stat & DRQ_STAT) && rq_data_dir(rq) == READ) { + int i; + + for (i = (drive->mult_count ? drive->mult_count : 1); i > 0; --i) { + u32 buffer[SECTOR_WORDS]; + + ata_read(drive, buffer, SECTOR_WORDS); + } + } } + /* Force an abort if not even the status data is available. This will + * clear all pending IRQs on the drive as well. + */ if (!ata_status(drive, 0, BUSY_STAT | DRQ_STAT)) - OUT_BYTE(WIN_IDLEIMMEDIATE, IDE_COMMAND_REG); /* force an abort */ + OUT_BYTE(WIN_IDLEIMMEDIATE, IDE_COMMAND_REG); + /* Bail out immediately. */ if (rq->errors >= ERROR_MAX) { printk(KERN_ERR "%s: max number of retries exceeded!\n", drive->name); if (ata_ops(drive) && ata_ops(drive)->end_request) ata_ops(drive)->end_request(drive, rq, 0); else - __ata_end_request(drive, rq, 0, 0); - } else { - ++rq->errors; - if ((rq->errors & ERROR_RESET) == ERROR_RESET) - return do_reset1(drive, 1); - if ((rq->errors & ERROR_RECAL) == ERROR_RECAL) - /* FIXME: tries to acquire the channel lock -Zwane */ - return do_recalibrate(drive); - } - - return ATA_OP_FINISHED; -} - -/* - * This initiates handling of a new I/O request. - */ -static ide_startstop_t start_request(struct ata_device *drive, struct request *rq) -{ - struct ata_channel *ch = drive->channel; - sector_t block; - unsigned int minor = minor(rq->rq_dev); - unsigned int unit = minor >> PARTN_BITS; - ide_startstop_t ret; - - BUG_ON(!(rq->flags & REQ_STARTED)); - -#ifdef DEBUG - printk("%s: %s: current=0x%08lx\n", ch->name, __FUNCTION__, (unsigned long) rq); -#endif - - /* bail early if we've exceeded max_failures */ - if (drive->max_failures && (drive->failures > drive->max_failures)) - goto kill_rq; + ata_end_request(drive, rq, 0, 0); - if (unit >= MAX_DRIVES) { - printk(KERN_ERR "%s: bad device number: %s\n", ch->name, kdevname(rq->rq_dev)); - goto kill_rq; + return ATA_OP_FINISHED; } - block = rq->sector; + ++rq->errors; + printk(KERN_INFO "%s: request error, nr. %d\n", drive->name, rq->errors); - /* Strange disk manager remap. + /* + * Attempt to recover a confused drive by resetting it. Unfortunately, + * resetting a disk drive actually resets all devices on the same + * interface, so it can really be thought of as resetting the interface + * rather than resetting the drive. + * + * ATAPI devices have their own reset mechanism which allows them to be + * individually reset without clobbering other devices on the same + * interface. + * + * The IDE interface does not generate an interrupt to let us know when + * the reset operation has finished, so we must poll for this. This + * may take a very long time to complete. + * + * Maybe we can check if we are in IRQ context and schedule the CPU + * during this time. But for certain we should block all data transfers + * on the channel in question during those operations. */ - if (rq->flags & REQ_CMD) - if (drive->type == ATA_DISK || drive->type == ATA_FLOPPY) - block += drive->sect0; - /* Yecch - this will shift the entire interval, possibly killing some - * innocent following sector. - */ - if (block == 0 && drive->remap_0_to_1 == 1) - block = 1; /* redirect MBR access to EZ-Drive partn table */ + if ((rq->errors & ERROR_RESET) == ERROR_RESET) { + unsigned int unit; + struct ata_channel *ch = drive->channel; + int ret; - ata_select(drive, 0); - ret = ata_status_poll(drive, drive->ready_stat, BUSY_STAT | DRQ_STAT, - WAIT_READY, rq); - if (ret != ATA_OP_READY) { - printk(KERN_WARNING "%s: drive not ready for command\n", drive->name); + /* For an ATAPI device, first try an ATAPI SRST. + */ - goto kill_rq; - } + if (drive->type != ATA_DISK) { + check_crc_errors(drive); + ata_select(drive, 20); + udelay(1); + ata_irq_enable(drive, 0); + OUT_BYTE(WIN_SRST, IDE_COMMAND_REG); + if (drive->quirk_list == 2) + ata_irq_enable(drive, 1); + udelay(1); + ret = ata_status_poll(drive, 0, BUSY_STAT, WAIT_WORSTCASE, NULL); + ata_mask(drive); + + if (ret == ATA_OP_READY) { + printk("%s: ATAPI reset complete\n", drive->name); + + return ATA_OP_CONTINUES; + } else + printk(KERN_ERR "%s: ATAPI reset timed out, status=0x%02x\n", + drive->name, drive->status); + } - if (!ata_ops(drive)) { - printk(KERN_WARNING "%s: device type %d not supported\n", - drive->name, drive->type); - goto kill_rq; - } + /* Reset all devices on channel. + */ - /* The normal way of execution is to pass and execute the request - * handler down to the device type driver. - */ + /* First, reset any device state data we were maintaining for + * any of the drives on this interface. + */ + for (unit = 0; unit < MAX_DRIVES; ++unit) + check_crc_errors(&ch->drives[unit]); - if (ata_ops(drive)->do_request) { - ret = ata_ops(drive)->do_request(drive, rq, block); - } else { - __ata_end_request(drive, rq, 0, 0); - ret = ATA_OP_FINISHED; - } - return ret; + /* And now actually perform the reset operation. + */ + printk("%s: ATA reset...\n", ch->name); + ata_select(drive, 20); + udelay(1); + ata_irq_enable(drive, 0); -kill_rq: - if (ata_ops(drive) && ata_ops(drive)->end_request) - ata_ops(drive)->end_request(drive, rq, 0); - else - __ata_end_request(drive, rq, 0, 0); + /* This command actually looks suspicious, since I couldn't + * find it in any standard document. + */ + OUT_BYTE(0x04, ch->io_ports[IDE_CONTROL_OFFSET]); + udelay(10); + OUT_BYTE(WIN_NOP, ch->io_ports[IDE_CONTROL_OFFSET]); + ret = ata_status_poll(drive, 0, BUSY_STAT, WAIT_WORSTCASE, NULL); + ata_mask(drive); + + if (ret == ATA_OP_READY) + printk("%s: ATA reset complete\n", drive->name); + else + printk(KERN_ERR "%s: ATA reset timed out, status=0x%02x\n", + drive->name, drive->status); + mdelay(100); + } - return ATA_OP_FINISHED; + /* signal that we should retry this request */ + return ATA_OP_CONTINUES; } /* @@ -689,218 +511,255 @@ void ide_stall_queue(struct ata_device *drive, unsigned long timeout) drive->sleep = timeout + jiffies; } - /* - * Determine the longest sleep time for the devices at this channel. + * Issue a new request. + * Caller must have already done spin_lock_irqsave(channel->lock, ...) */ -static unsigned long longest_sleep(struct ata_channel *channel) +static void do_request(struct ata_channel *channel) { - unsigned long sleep = 0; - int unit; - - for (unit = 0; unit < MAX_DRIVES; ++unit) { - struct ata_device *drive = &channel->drives[unit]; - - if (!drive->present) - continue; - - /* This device is sleeping and waiting to be serviced - * later than any other device we checked thus far. - */ - if (drive->sleep && (!sleep || time_after(drive->sleep, sleep))) - sleep = drive->sleep; - } + struct ata_channel *ch; + struct ata_device *drive = NULL; + unsigned int unit; + ide_startstop_t ret; - return sleep; -} + __cli(); /* necessary paranoia: ensure IRQs are masked on local CPU */ -/* - * Select the next device which will be serviced. This selects only between - * devices on the same channel, since everything else will be scheduled on the - * queue level. - */ -static struct ata_device *choose_urgent_device(struct ata_channel *channel) -{ - struct ata_device *choice = NULL; - unsigned long sleep = 0; - int unit; + /* + * Select the next device which will be serviced. This selects + * only between devices on the same channel, since everything + * else will be scheduled on the queue level. + */ for (unit = 0; unit < MAX_DRIVES; ++unit) { - struct ata_device *drive = &channel->drives[unit]; + struct ata_device *tmp = &channel->drives[unit]; - if (!drive->present) + if (!tmp->present) continue; - /* There are no request pending for this device. + /* There are no requests pending for this device. */ - if (blk_queue_empty(&drive->queue)) + if (blk_queue_empty(&tmp->queue)) continue; + /* This device still wants to remain idle. */ - if (drive->sleep && time_after(drive->sleep, jiffies)) + if (tmp->sleep && time_after(tmp->sleep, jiffies)) continue; - /* Take this device, if there is no device choosen thus far or - * it's more urgent. + /* Take this device, if there is no device choosen thus + * far or which is more urgent. */ - if (!choice || (drive->sleep && (!choice->sleep || time_after(choice->sleep, drive->sleep)))) { - if (!blk_queue_plugged(&drive->queue)) - choice = drive; + if (!drive || (tmp->sleep && (!drive->sleep || time_after(drive->sleep, tmp->sleep)))) { + if (!blk_queue_plugged(&tmp->queue)) + drive = tmp; } } - if (choice) - return choice; + if (!drive) { + unsigned long sleep = 0; - sleep = longest_sleep(channel); + for (unit = 0; unit < MAX_DRIVES; ++unit) { + struct ata_device *tmp = &channel->drives[unit]; + + if (!tmp->present) + continue; - if (sleep) { + /* This device is sleeping and waiting to be serviced + * earlier than any other device we checked thus far. + */ + if (tmp->sleep && (!sleep || time_after(sleep, tmp->sleep))) + sleep = tmp->sleep; + } - /* - * Take a short snooze, and then wake up again. Just in case - * there are big differences in relative throughputs.. don't - * want to hog the cpu too much. - */ + if (sleep) { + /* + * Take a short snooze, and then wake up again. Just + * in case there are big differences in relative + * throughputs.. don't want to hog the cpu too much. + */ - if (time_after(jiffies, sleep - WAIT_MIN_SLEEP)) - sleep = jiffies + WAIT_MIN_SLEEP; + if (time_after(jiffies, sleep - WAIT_MIN_SLEEP)) + sleep = jiffies + WAIT_MIN_SLEEP; #if 1 - if (timer_pending(&channel->timer)) - printk(KERN_ERR "%s: timer already active\n", __FUNCTION__); + if (timer_pending(&channel->timer)) + printk(KERN_ERR "%s: timer already active\n", __FUNCTION__); #endif - set_bit(IDE_SLEEP, channel->active); - mod_timer(&channel->timer, sleep); - /* we purposely leave hwgroup busy while sleeping */ - } else { - /* FIXME: use queue plugging instead of active to - * block upper layers from stomping on us */ - /* Ugly, but how can we sleep for the lock otherwise? */ - ide_release_lock(&ide_irq_lock);/* for atari only */ - clear_bit(IDE_BUSY, channel->active); - } + set_bit(IDE_SLEEP, channel->active); + mod_timer(&channel->timer, sleep); - return NULL; -} + /* + * We purposely leave us busy while sleeping becouse we + * are prepared to handle the IRQ from it. + * + * FIXME: Make sure sleeping can't interferre with + * operations of other devices on the same channel. + */ + } else { + /* FIXME: use queue plugging instead of active to block + * upper layers from stomping on us */ + /* Ugly, but how can we sleep for the lock otherwise? + * */ + + ide_release_lock(&ide_irq_lock);/* for atari only */ + clear_bit(IDE_BUSY, channel->active); + + /* All requests are done. + * + * Disable IRQs from the last drive on this channel, to + * make sure that it wan't throw stones at us when we + * are not prepared to take them. + */ -/* - * Issue a new request. - * Caller must have already done spin_lock_irqsave(channel->lock, ...) - */ -static void do_request(struct ata_channel *channel) -{ - ide_get_lock(&ide_irq_lock, ata_irq_request, channel);/* for atari only: POSSIBLY BROKEN HERE(?) */ - __cli(); /* necessary paranoia: ensure IRQs are masked on local CPU */ + if (channel->drive && !channel->drive->using_tcq) + ata_irq_enable(channel->drive, 0); + } - while (!test_and_set_bit(IDE_BUSY, channel->active)) { - struct ata_channel *ch; - struct ata_device *drive; - struct request *rq = NULL; - ide_startstop_t startstop; - int i; + return; + } - /* this will clear IDE_BUSY, if appropriate */ - drive = choose_urgent_device(channel); + /* Remember the last drive we where acting on. + */ + ch = drive->channel; + ch->drive = drive; - if (!drive) - break; + /* Feed commands to a drive until it barfs. + */ + do { + struct request *rq = NULL; + sector_t block; - /* Remember the last drive we where acting on. + /* Abort early if we can't queue another command. for non tcq, + * ata_can_queue is always 1 since we never get here unless the + * drive is idle. */ - ch = drive->channel; - ch->drive = drive; - /* Make sure that all drives on channels sharing the IRQ line - * with us won't generate IRQ's during our activity. - */ - for (i = 0; i < MAX_HWIFS; ++i) { - struct ata_channel *tmp = &ide_hwifs[i]; - int j; + if (!ata_can_queue(drive)) { + if (!ata_pending_commands(drive)) { + clear_bit(IDE_BUSY, ch->active); + if (drive->using_tcq) + ata_irq_enable(drive, 0); + } + break; + } - if (!tmp->present) - continue; + drive->sleep = 0; - if (ch->lock != tmp->lock) - continue; + if (test_bit(IDE_DMA, ch->active)) { + printk(KERN_ERR "%s: error: DMA in progress...\n", drive->name); + break; + } - /* Only care if there is any drive on the channel in - * question. - */ - for (j = 0; j < MAX_DRIVES; ++j) { - struct ata_device * other = &tmp->drives[j]; + /* There's a small window between where the queue could be + * replugged while we are in here when using tcq (in which case + * the queue is probably empty anyways...), so check and leave + * if appropriate. When not using tcq, this is still a severe + * BUG! + */ + + if (blk_queue_plugged(&drive->queue)) { + BUG_ON(!drive->using_tcq); + break; + } - if (other->present) - ata_irq_enable(other, 0); + if (!(rq = elv_next_request(&drive->queue))) { + if (!ata_pending_commands(drive)) { + clear_bit(IDE_BUSY, ch->active); + if (drive->using_tcq) + ata_irq_enable(drive, 0); } + drive->rq = NULL; + + break; } + /* If there are queued commands, we can't start a + * non-fs request (really, a non-queuable command) + * until the queue is empty. + */ + if (!(rq->flags & REQ_CMD) && ata_pending_commands(drive)) + break; + + drive->rq = rq; + + spin_unlock(ch->lock); + ide__sti(); /* allow other IRQs while we start this request */ + /* - * Feed commands to a drive until it barfs. + * This initiates handling of a new I/O request. */ - do { - if (!test_bit(IDE_BUSY, ch->active)) - printk(KERN_ERR "%s: error: not busy while queueing!\n", drive->name); - /* Abort early if we can't queue another command. for - * non tcq, ata_can_queue is always 1 since we never - * get here unless the drive is idle. - */ - if (!ata_can_queue(drive)) { - if (!ata_pending_commands(drive)) - clear_bit(IDE_BUSY, ch->active); - break; - } + BUG_ON(!(rq->flags & REQ_STARTED)); - drive->sleep = 0; +#ifdef DEBUG + printk("%s: %s: current=0x%08lx\n", ch->name, __FUNCTION__, (unsigned long) rq); +#endif - if (test_bit(IDE_DMA, ch->active)) { - printk(KERN_ERR "%s: error: DMA in progress...\n", drive->name); - break; - } + /* bail early if we've exceeded max_failures */ + if (drive->max_failures && (drive->failures > drive->max_failures)) + goto kill_rq; - /* There's a small window between where the queue could - * be replugged while we are in here when using tcq (in - * which case the queue is probably empty anyways...), - * so check and leave if appropriate. When not using - * tcq, this is still a severe BUG! - */ - if (blk_queue_plugged(&drive->queue)) { - BUG_ON(!drive->using_tcq); - break; - } + block = rq->sector; - if (!(rq = elv_next_request(&drive->queue))) { - if (!ata_pending_commands(drive)) - clear_bit(IDE_BUSY, ch->active); - drive->rq = NULL; - break; - } + /* Strange disk manager remap. + */ + if (rq->flags & REQ_CMD) + if (drive->type == ATA_DISK || drive->type == ATA_FLOPPY) + block += drive->sect0; - /* If there are queued commands, we can't start a - * non-fs request (really, a non-queuable command) - * until the queue is empty. - */ - if (!(rq->flags & REQ_CMD) && ata_pending_commands(drive)) - break; + /* Yecch - this will shift the entire interval, possibly killing some + * innocent following sector. + */ + if (block == 0 && drive->remap_0_to_1 == 1) + block = 1; /* redirect MBR access to EZ-Drive partn table */ + + ata_select(drive, 0); + ret = ata_status_poll(drive, drive->ready_stat, BUSY_STAT | DRQ_STAT, + WAIT_READY, rq); + + if (ret != ATA_OP_READY) { + printk(KERN_ERR "%s: drive not ready for command\n", drive->name); + + goto kill_rq; + } + + if (!ata_ops(drive)) { + printk(KERN_WARNING "%s: device type %d not supported\n", + drive->name, drive->type); + goto kill_rq; + } - drive->rq = rq; + /* The normal way of execution is to pass and execute the request + * handler down to the device type driver. + */ + + if (ata_ops(drive)->do_request) { + ret = ata_ops(drive)->do_request(drive, rq, block); + } else { +kill_rq: + if (ata_ops(drive) && ata_ops(drive)->end_request) + ata_ops(drive)->end_request(drive, rq, 0); + else + ata_end_request(drive, rq, 0, 0); + ret = ATA_OP_FINISHED; - spin_unlock(ch->lock); - ide__sti(); /* allow other IRQs while we start this request */ - startstop = start_request(drive, rq); - spin_lock_irq(ch->lock); + } + spin_lock_irq(ch->lock); - /* command started, we are busy */ - } while (startstop != ATA_OP_CONTINUES); - /* make sure the BUSY bit is set */ - /* FIXME: perhaps there is some place where we miss to set it? */ + /* continue if command started, so we are busy */ + } while (ret != ATA_OP_CONTINUES); + /* make sure the BUSY bit is set */ + /* FIXME: perhaps there is some place where we miss to set it? */ // set_bit(IDE_BUSY, ch->active); - } } void do_ide_request(request_queue_t *q) { - do_request(q->queuedata); + struct ata_channel *ch = q->queuedata; + + while (!test_and_set_bit(IDE_BUSY, ch->active)) { + do_request(ch); + } } /* @@ -908,7 +767,8 @@ void do_ide_request(request_queue_t *q) * also be invoked as a result of a "sleep" operation triggered by the * mod_timer() call in do_request. * - * FIXME: this should take a drive context instead of a channel. + * FIXME: This should take a drive context instead of a channel. + * FIXME: This should not explicitly reenter the request handling engine. */ void ide_timer_expiry(unsigned long data) { @@ -928,6 +788,8 @@ void ide_timer_expiry(unsigned long data) * as timer expired), or we were "sleeping" to give other * devices a chance. Either way, we don't really want to * complain about anything. + * + * FIXME: Do we really still have to clear IDE_BUSY here? */ if (test_and_clear_bit(IDE_SLEEP, ch->active)) @@ -979,7 +841,7 @@ void ide_timer_expiry(unsigned long data) __cli(); /* local CPU only, as if we were handling an interrupt */ if (ch->poll_timeout) { ret = handler(drive, drive->rq); - } else if (drive_is_ready(drive)) { + } else if (ata_status_irq(drive)) { if (test_bit(IDE_DMA, ch->active)) udma_irq_lost(drive); (void) ide_ack_intr(ch); @@ -1026,11 +888,10 @@ void ide_timer_expiry(unsigned long data) enable_irq(ch->irq); spin_lock_irq(ch->lock); - if (ret == ATA_OP_FINISHED) - clear_bit(IDE_BUSY, ch->active); - - /* Reenter the request handling engine */ - do_request(ch); + if (ret == ATA_OP_FINISHED) { + /* Reenter the request handling engine. */ + do_request(ch); + } } spin_unlock_irqrestore(ch->lock, flags); } @@ -1060,32 +921,35 @@ void ide_timer_expiry(unsigned long data) */ static void unexpected_irq(int irq) { + /* Try to not flood the console with msgs */ + static unsigned long last_msgtime; /* = 0 */ + static int count; /* = 0 */ int i; for (i = 0; i < MAX_HWIFS; ++i) { struct ata_channel *ch = &ide_hwifs[i]; + int j; struct ata_device *drive; - if (!ch->present) + if (!ch->present || ch->irq != irq) continue; - if (ch->irq != irq) - continue; + for (j = 0; j < MAX_DRIVES; ++j) { + drive = &ch->drives[j]; - /* FIXME: this is a bit weak */ - drive = &ch->drives[0]; - - if (!ata_status(drive, READY_STAT, BAD_STAT)) { - /* Try to not flood the console with msgs */ - static unsigned long last_msgtime; - static int count; + /* this drive is idle */ + if (ata_status(drive, READY_STAT, BAD_STAT)) + continue; ++count; - if (time_after(jiffies, last_msgtime + HZ)) { - last_msgtime = jiffies; - printk("%s: unexpected interrupt, status=0x%02x, count=%d\n", - ch->name, drive->status, count); - } + + /* don't report too frequently */ + if (!time_after(jiffies, last_msgtime + HZ)) + continue; + + last_msgtime = jiffies; + printk("%s: unexpected interrupt, status=0x%02x, count=%d\n", + ch->name, drive->status, count); } } } @@ -1099,7 +963,7 @@ void ata_irq_request(int irq, void *data, struct pt_regs *regs) unsigned long flags; struct ata_device *drive; ata_handler_t *handler; - ide_startstop_t startstop; + ide_startstop_t ret; spin_lock_irqsave(ch->lock, flags); @@ -1107,53 +971,53 @@ void ata_irq_request(int irq, void *data, struct pt_regs *regs) goto out_lock; handler = ch->handler; - if (handler == NULL || ch->poll_timeout != 0) { + drive = ch->drive; + if (!handler || ch->poll_timeout) { #if 0 printk(KERN_INFO "ide: unexpected interrupt %d %d\n", ch->unit, irq); #endif + /* - * Not expecting an interrupt from this drive. - * That means this could be: - * (1) an interrupt from another PCI device - * sharing the same PCI INT# as us. - * or (2) a drive just entered sleep or standby mode, - * and is interrupting to let us know. - * or (3) a spurious interrupt of unknown origin. + * Not expecting an interrupt from this drive. That means this + * could be: + * + * - an interrupt from another PCI device sharing the same PCI + * INT# as us. * - * For PCI, we cannot tell the difference, - * so in that case we just ignore it and hope it goes away. + * - a drive just entered sleep or standby mode, and is + * interrupting to let us know. + * + * - a spurious interrupt of unknown origin. + * + * For PCI, we cannot tell the difference, so in that case we + * just clear it and hope it goes away. */ + #ifdef CONFIG_PCI if (ch->pci_dev && !ch->pci_dev->vendor) #endif - { - /* Probably not a shared PCI interrupt, so we can - * safely try to do something about it: - */ unexpected_irq(irq); #ifdef CONFIG_PCI - } else { - /* - * Whack the status register, just in case we have a leftover pending IRQ. - */ - IN_BYTE(ch->io_ports[IDE_STATUS_OFFSET]); + else + ata_status(drive, READY_STAT, BAD_STAT); #endif - } + goto out_lock; } - drive = ch->drive; - if (!drive_is_ready(drive)) { - /* - * This happens regularly when we share a PCI IRQ with another device. + if (!ata_status_irq(drive)) { + /* This happens regularly when we share a PCI IRQ with another device. * Unfortunately, it can also happen with some buggy drives that trigger * the IRQ before their status register is up to date. Hopefully we have * enough advance overhead that the latter isn't a problem. */ + goto out_lock; } + /* paranoia */ if (!test_and_set_bit(IDE_BUSY, ch->active)) - printk(KERN_ERR "%s: %s: hwgroup was not busy!?\n", drive->name, __FUNCTION__); + printk(KERN_ERR "%s: %s: channel was not busy!?\n", drive->name, __FUNCTION__); + ch->handler = NULL; del_timer(&ch->timer); @@ -1162,25 +1026,32 @@ void ata_irq_request(int irq, void *data, struct pt_regs *regs) if (ch->unmask) ide__sti(); - /* service this interrupt, may set handler for next interrupt */ - startstop = handler(drive, drive->rq); + /* + * Service this interrupt, this may setup handler for next interrupt. + */ + ret = handler(drive, drive->rq); spin_lock_irq(ch->lock); /* - * Note that handler() may have set things up for another - * interrupt to occur soon, but it cannot happen until - * we exit from this routine, because it will be the - * same irq as is currently being serviced here, and Linux - * won't allow another of the same (on any CPU) until we return. + * Note that handler() may have set things up for another interrupt to + * occur soon, but it cannot happen until we exit from this routine, + * because it will be the same irq as is currently being serviced here, + * and Linux won't allow another of the same (on any CPU) until we + * return. */ - if (startstop == ATA_OP_FINISHED) { - if (!ch->handler) { /* paranoia */ - clear_bit(IDE_BUSY, ch->active); + + if (ret == ATA_OP_FINISHED) { + + /* Reenter the request handling engine if we are not expecting + * another interrupt. + */ + + if (!ch->handler) do_request(ch); - } else { - printk("%s: %s: huh? expected NULL handler on exit\n", drive->name, __FUNCTION__); - } + else + printk("%s: %s: huh? expected NULL handler on exit\n", + drive->name, __FUNCTION__); } out_lock: @@ -1202,7 +1073,7 @@ static int ide_open(struct inode * inode, struct file * filp) */ #ifdef CONFIG_KMOD - if (drive->driver == NULL) { + if (!drive->driver) { char *module = NULL; switch (drive->type) { @@ -1263,6 +1134,7 @@ static int ide_release(struct inode * inode, struct file * file) drive->usage--; if (ata_ops(drive) && ata_ops(drive)->release) ata_ops(drive)->release(inode, file, drive); + return 0; } @@ -1332,7 +1204,7 @@ EXPORT_SYMBOL(ata_set_handler); EXPORT_SYMBOL(ata_dump); EXPORT_SYMBOL(ata_error); -EXPORT_SYMBOL(__ata_end_request); +EXPORT_SYMBOL(ata_end_request); EXPORT_SYMBOL(ide_stall_queue); EXPORT_SYMBOL(ide_setup_ports); diff --git a/drivers/ide/main.c b/drivers/ide/main.c index 96fb19d3f89d..24cc8bc9a75e 100644 --- a/drivers/ide/main.c +++ b/drivers/ide/main.c @@ -140,12 +140,9 @@ struct ata_channel ide_hwifs[MAX_HWIFS]; /* master data repository */ * Setup hw_regs_t structure described by parameters. You may set up the hw * structure yourself OR use this routine to do it for you. */ -void ide_setup_ports(hw_regs_t *hw, - ide_ioreg_t base, - int *offsets, - ide_ioreg_t ctrl, - ide_ioreg_t intr, - ide_ack_intr_t *ack_intr, +void ide_setup_ports(hw_regs_t *hw, ide_ioreg_t base, int *offsets, + ide_ioreg_t ctrl, ide_ioreg_t intr, + int (*ack_intr)(struct ata_channel *), int irq) { int i; @@ -637,17 +634,6 @@ found: * FIXME: rewrite the following crap: */ -/* - * stridx() returns the offset of c within s, - * or -1 if c is '\0' or not found within s. - */ -static int __init stridx (const char *s, char c) -{ - char *i = strchr(s, c); - - return (i && c) ? i - s : -1; -} - /* * Parsing for ide_setup(): * @@ -657,14 +643,14 @@ static int __init stridx (const char *s, char c) * 3. if the remainder is a series of no more than max_vals numbers * separated by commas, the numbers are saved in vals[] and a * count of how many were saved is returned. Base10 is assumed, - * and base16 is allowed when prefixed with "0x". + * and base16 is allowed when prefixed with "0x". The number of + * values read will be placed in vals[0], and the values read will + * placed in vals[1] to vals[max_vals]. * 4. otherwise, zero is returned. */ static int __init match_parm (char *s, const char *keywords[], int vals[], int max_vals) { - static const char decimal[] = "0123456789"; - static const char hex[] = "0123456789abcdef"; - int i, n; + int i; if (*s++ == '=') { /* @@ -683,23 +669,10 @@ static int __init match_parm (char *s, const char *keywords[], int vals[], int m * or base16 when prefixed with "0x". * Return a count of how many were found. */ - for (n = 0; (i = stridx(decimal, *s)) >= 0;) { - vals[n] = i; - while ((i = stridx(decimal, *++s)) >= 0) - vals[n] = (vals[n] * 10) + i; - if (*s == 'x' && !vals[n]) { - while ((i = stridx(hex, *++s)) >= 0) - vals[n] = (vals[n] * 0x10) + i; - } - if (++n == max_vals) - break; - if (*s == ',' || *s == ';') - ++s; - } - if (!*s) - return n; + get_options(s, max_vals+1, vals); + return vals[0]; } - return 0; /* zero = nothing matched */ + return 0; } /* @@ -744,7 +717,7 @@ static void __init init_global_data(void) */ int __init ide_setup(char *s) { - int i, vals[3]; + int i, vals[4]; struct ata_channel *ch; struct ata_device *drive; unsigned int hw, unit; @@ -755,7 +728,6 @@ int __init ide_setup(char *s) return 0; if (strncmp(s,"ide",3) && - strncmp(s,"idebus",6) && strncmp(s,"hd",2)) /* hdx= & hdxlun= */ return 0; @@ -801,24 +773,24 @@ int __init ide_setup(char *s) unit = unit % MAX_DRIVES; ch = &ide_hwifs[hw]; drive = &ch->drives[unit]; - if (!strncmp(s + 4, "ide-", 4)) { + if (!strncmp(s+3, "=ide-", 5)) { strncpy(drive->driver_req, s + 4, 9); goto done; } /* * Look for last lun option: "hdxlun=" */ - if (!strncmp(&s[3], "lun", 3)) { - if (match_parm(&s[6], NULL, vals, 1) != 1) + if (!strncmp(s+3, "lun=", 4)) { + if (*get_options(s+7, 2, vals) || vals[0]!=1) goto bad_option; - if (vals[0] >= 0 && vals[0] <= 7) { - drive->last_lun = vals[0]; + if (vals[1] >= 0 && vals[1] <= 7) { + drive->last_lun = vals[1]; drive->forced_lun = 1; } else printk(" -- BAD LAST LUN! Expected value from 0 to 7"); goto done; } - switch (match_parm(&s[3], hd_words, vals, 3)) { + switch (match_parm(s+3, hd_words, vals, 3)) { case -1: /* "none" */ drive->nobios = 1; /* drop into "noprobe" */ case -2: /* "noprobe" */ @@ -864,9 +836,9 @@ int __init ide_setup(char *s) #endif case 3: /* cyl,head,sect */ drive->type = ATA_DISK; - drive->cyl = drive->bios_cyl = vals[0]; - drive->head = drive->bios_head = vals[1]; - drive->sect = drive->bios_sect = vals[2]; + drive->cyl = drive->bios_cyl = vals[1]; + drive->head = drive->bios_head = vals[2]; + drive->sect = drive->bios_sect = vals[3]; drive->present = 1; drive->forced_geom = 1; ch->noprobe = 0; @@ -879,10 +851,10 @@ int __init ide_setup(char *s) /* * Look for bus speed option: "idebus=" */ - if (!strncmp(s, "idebus", 6)) { - if (match_parm(&s[6], NULL, vals, 1) != 1) + if (!strncmp(s, "idebus=", 7)) { + if (*get_options(s+7, 2, vals) || vals[0] != 1) goto bad_option; - idebus_parameter = vals[0]; + idebus_parameter = vals[1]; goto done; } @@ -892,33 +864,72 @@ int __init ide_setup(char *s) if (!strncmp(s, "ide", 3) && s[3] >= '0' && s[3] <= max_ch) { /* * Be VERY CAREFUL changing this: note hardcoded indexes below - * -8,-9,-10. -11 : are reserved for future idex calls to ease the hardcoding. */ + const char *ide_options[] = { + "noprobe", "serialize", "autotune", "noautotune", "reset", "dma", "ata66", NULL }; const char *ide_words[] = { - "noprobe", "serialize", "autotune", "noautotune", "reset", "dma", "ata66", - "minus8", "minus9", "minus10", "minus11", "qd65xx", "ht6560b", "cmd640_vlb", "dtc2278", "umc8672", "ali14xx", "dc4030", NULL }; hw = s[3] - '0'; ch = &ide_hwifs[hw]; + + switch (match_parm(s+4, ide_options, vals, 1)) { + case -7: /* ata66 */ +#ifdef CONFIG_PCI + ch->udma_four = 1; + goto done; +#else + ch->udma_four = 0; + goto bad_channel; +#endif + case -6: /* dma */ + ch->autodma = 1; + goto done; + case -5: /* reset */ + ch->reset = 1; + goto done; + case -4: /* noautotune */ + ch->drives[0].autotune = 2; + ch->drives[1].autotune = 2; + goto done; + case -3: /* autotune */ + ch->drives[0].autotune = 1; + ch->drives[1].autotune = 1; + goto done; + case -2: /* "serialize" */ + do_serialize: + { + struct ata_channel *mate; + + mate = &ide_hwifs[hw ^ 1]; + ch->serialized = 1; + mate->serialized = 1; + } + goto done; + + case -1: /* "noprobe" */ + ch->noprobe = 1; + goto done; + } + i = match_parm(&s[4], ide_words, vals, 3); /* * Cryptic check to ensure chipset not already set for a channel: */ - if (i > 0 || i <= -11) { /* is parameter a chipset name? */ - if (ch->chipset != ide_unknown) + if (i) { /* is parameter a chipset name? */ + if (ide_hwifs[hw].chipset != ide_unknown) goto bad_option; /* chipset already specified */ - if (i <= -11 && i != -18 && hw != 0) + if (i != -7 && hw != 0) goto bad_channel; /* chipset drivers are for "ide0=" only */ - if (i <= -11 && i != -18 && ide_hwifs[hw+1].chipset != ide_unknown) + if (i != -7 && ide_hwifs[1].chipset != ide_unknown) goto bad_option; /* chipset for 2nd port already specified */ printk("\n"); } switch (i) { #ifdef CONFIG_BLK_DEV_PDC4030 - case -18: /* "dc4030" */ + case -7: /* "dc4030" */ { extern void init_pdc4030(void); init_pdc4030(); @@ -926,7 +937,7 @@ int __init ide_setup(char *s) } #endif #ifdef CONFIG_BLK_DEV_ALI14XX - case -17: /* "ali14xx" */ + case -6: /* "ali14xx" */ { extern void init_ali14xx (void); init_ali14xx(); @@ -934,7 +945,7 @@ int __init ide_setup(char *s) } #endif #ifdef CONFIG_BLK_DEV_UMC8672 - case -16: /* "umc8672" */ + case -5: /* "umc8672" */ { extern void init_umc8672 (void); init_umc8672(); @@ -942,7 +953,7 @@ int __init ide_setup(char *s) } #endif #ifdef CONFIG_BLK_DEV_DTC2278 - case -15: /* "dtc2278" */ + case -4: /* "dtc2278" */ { extern void init_dtc2278 (void); init_dtc2278(); @@ -950,7 +961,7 @@ int __init ide_setup(char *s) } #endif #ifdef CONFIG_BLK_DEV_CMD640 - case -14: /* "cmd640_vlb" */ + case -3: /* "cmd640_vlb" */ { extern int cmd640_vlb; /* flag for cmd640.c */ cmd640_vlb = 1; @@ -958,7 +969,7 @@ int __init ide_setup(char *s) } #endif #ifdef CONFIG_BLK_DEV_HT6560B - case -13: /* "ht6560b" */ + case -2: /* "ht6560b" */ { extern void init_ht6560b (void); init_ht6560b(); @@ -966,64 +977,22 @@ int __init ide_setup(char *s) } #endif #if CONFIG_BLK_DEV_QD65XX - case -12: /* "qd65xx" */ + case -1: /* "qd65xx" */ { extern void init_qd65xx (void); init_qd65xx(); goto done; } #endif - case -11: /* minus11 */ - case -10: /* minus10 */ - case -9: /* minus9 */ - case -8: /* minus8 */ - goto bad_option; - case -7: /* ata66 */ -#ifdef CONFIG_PCI - ch->udma_four = 1; - goto done; -#else - ch->udma_four = 0; - goto bad_channel; -#endif - case -6: /* dma */ - ch->autodma = 1; - goto done; - case -5: /* reset */ - ch->reset = 1; - goto done; - case -4: /* noautotune */ - ch->drives[0].autotune = 2; - ch->drives[1].autotune = 2; - goto done; - case -3: /* autotune */ - ch->drives[0].autotune = 1; - ch->drives[1].autotune = 1; - goto done; - case -2: /* "serialize" */ - do_serialize: - { - struct ata_channel *mate; - - mate = &ide_hwifs[hw ^ 1]; - ch->serialized = 1; - mate->serialized = 1; - } - goto done; - - case -1: /* "noprobe" */ - ch->noprobe = 1; - goto done; - case 1: /* base */ - vals[1] = vals[0] + 0x206; /* default ctl */ + vals[2] = vals[1] + 0x206; /* default ctl */ case 2: /* base,ctl */ - vals[2] = 0; /* default irq = probe for it */ + vals[3] = 0; /* default irq = probe for it */ case 3: /* base,ctl,irq */ - ch->hw.irq = vals[2]; - ide_init_hwif_ports(&ch->hw, (ide_ioreg_t) vals[0], (ide_ioreg_t) vals[1], &ch->irq); + ch->hw.irq = vals[3]; + ide_init_hwif_ports(&ch->hw, (ide_ioreg_t) vals[1], (ide_ioreg_t) vals[2], &ch->irq); memcpy(ch->io_ports, ch->hw.io_ports, sizeof(ch->io_ports)); - ch->irq = vals[2]; + ch->irq = vals[3]; ch->noprobe = 0; ch->chipset = ide_generic; goto done; diff --git a/drivers/ide/pcidma.c b/drivers/ide/pcidma.c index 4dd11411110f..a476693a3820 100644 --- a/drivers/ide/pcidma.c +++ b/drivers/ide/pcidma.c @@ -46,7 +46,7 @@ ide_startstop_t ide_dma_intr(struct ata_device *drive, struct request *rq) if (ata_status(drive, DRIVE_READY, drive->bad_wstat | DRQ_STAT)) { if (!dma_stat) { - __ata_end_request(drive, rq, 1, rq->nr_sectors); + ata_end_request(drive, rq, 1, rq->nr_sectors); return ATA_OP_FINISHED; } @@ -510,7 +510,7 @@ int udma_pci_irq_status(struct ata_device *drive) void udma_pci_timeout(struct ata_device *drive) { - printk(KERN_ERR "ATA: UDMA timeout occured %s!\n", drive->name); + printk(KERN_ERR "%s: UDMA timeout!\n", drive->name); } void udma_pci_irq_lost(struct ata_device *drive) diff --git a/drivers/ide/pdc202xx.c b/drivers/ide/pdc202xx.c index df7ede3b83ce..940ce70f6e30 100644 --- a/drivers/ide/pdc202xx.c +++ b/drivers/ide/pdc202xx.c @@ -3,10 +3,11 @@ * linux/drivers/ide/pdc202xx.c Version 0.30 May. 28, 2002 * * Copyright (C) 1998-2000 Andre Hedrick - * Copyright (C) 2002 Bartlomiej Zolnierkiewicz + * Copyright (C) 2002 BartÅ^Âomiej Å»oÅ^Ânierkiewicz * - * Portions Copyright (C) 1999 Promise Technology, Inc. - * Author: Frank Tiernan (frankt@promise.com) + * Portions Copyright (C) 1999-2002 Promise Technology, Inc. + * Author: Frank Tiernan + * Hank Yang * * May be copied or modified under the terms of the GNU General Public License * @@ -22,11 +23,21 @@ * * The latest chipset code will support the following :: * Three Ultra33 controllers and 12 drives. + * * 8 are UDMA supported and 4 are limited to DMA mode 2 multi-word. * The 8/4 ratio is a BIOS code limit by promise. * * UNLESS you enable "CONFIG_PDC202XX_BURST" * + * History: + * Sync 2.5 driver with Promise 2.4 driver v1.20.0.7 (07/11/02): + * - Add PDC20271 support + * - Disable LBA48 support on PDC20262 + * - Fix ATAPI UDMA port value + * - Add new quirk drive + * - Adjust timings for all drives when using ATA133 + * - Update pdc202xx_reset() waiting time + * */ #include @@ -108,6 +119,8 @@ static void pdc_dump_bits(struct pdc_bit_messages *msgs, byte bits) } #endif /* PDC202XX_DECODE_REGISTER_INFO */ +static struct ata_device* drives[4]; + int check_in_drive_lists(struct ata_device *drive) { static const char *pdc_quirk_drives[] = { @@ -115,12 +128,14 @@ int check_in_drive_lists(struct ata_device *drive) "QUANTUM FIREBALLP KA6.4", "QUANTUM FIREBALLP KA9.1", "QUANTUM FIREBALLP LM20.4", + "QUANTUM FIREBALLP KX13.6", "QUANTUM FIREBALLP KX20.5", "QUANTUM FIREBALLP KX27.3", "QUANTUM FIREBALLP LM20.5", NULL }; - const char**list = pdc_quirk_drives; + + const char**list = pdc_quirk_drives; struct hd_driveid *id = drive->id; while (*list) @@ -136,6 +151,7 @@ static int __init pdc202xx_modes_map(struct ata_channel *ch) switch(ch->pci_dev->device) { case PCI_DEVICE_ID_PROMISE_20276: case PCI_DEVICE_ID_PROMISE_20275: + case PCI_DEVICE_ID_PROMISE_20271: case PCI_DEVICE_ID_PROMISE_20269: map |= XFER_UDMA_133; case PCI_DEVICE_ID_PROMISE_20268R: @@ -250,105 +266,125 @@ static int pdc202xx_tune_chipset(struct ata_device *drive, byte speed) static int pdc202xx_new_tune_chipset(struct ata_device *drive, byte speed) { struct ata_channel *hwif = drive->channel; -#ifdef CONFIG_BLK_DEV_IDEDMA - unsigned long indexreg = (hwif->dma_base + 1); - unsigned long datareg = (hwif->dma_base + 3); -#else u32 high_16 = pci_resource_start(hwif->pci_dev, 4); - unsigned long indexreg = high_16 + (hwif->unit ? 0x09 : 0x01); - unsigned long datareg = (indexreg + 2); -#endif /* CONFIG_BLK_DEV_IDEDMA */ - byte thold = 0x10; - byte adj = (drive->dn%2) ? 0x08 : 0x00; + u32 indexreg = high_16 + (hwif->unit ? 0x09 : 0x01); + u32 datareg = indexreg + 2; + + u8 adj = (drive->dn % 2) ? 0x08 : 0x00; + u8 thold = 0x10; + int err, i, j = hwif->unit ? 2 : 0; #ifdef CONFIG_BLK_DEV_IDEDMA + /* Setting tHOLD bit to 0 if using UDMA mode 2 */ if (speed == XFER_UDMA_2) { OUT_BYTE((thold + adj), indexreg); OUT_BYTE((IN_BYTE(datareg) & 0x7f), datareg); } - switch (speed) { - case XFER_UDMA_7: - speed = XFER_UDMA_6; - case XFER_UDMA_6: - set_2regs(0x10, 0x1a); - set_2regs(0x11, 0x01); - set_2regs(0x12, 0xcb); - break; - case XFER_UDMA_5: - set_2regs(0x10, 0x1a); - set_2regs(0x11, 0x02); - set_2regs(0x12, 0xcb); - break; - case XFER_UDMA_4: - set_2regs(0x10, 0x1a); - set_2regs(0x11, 0x03); - set_2regs(0x12, 0xcd); - break; - case XFER_UDMA_3: - set_2regs(0x10, 0x1a); - set_2regs(0x11, 0x05); - set_2regs(0x12, 0xcd); - break; - case XFER_UDMA_2: - set_2regs(0x10, 0x2a); - set_2regs(0x11, 0x07); - set_2regs(0x12, 0xcd); - break; - case XFER_UDMA_1: - set_2regs(0x10, 0x3a); - set_2regs(0x11, 0x0a); - set_2regs(0x12, 0xd0); - break; - case XFER_UDMA_0: - set_2regs(0x10, 0x4a); - set_2regs(0x11, 0x0f); - set_2regs(0x12, 0xd5); - break; - case XFER_MW_DMA_2: - set_2regs(0x0e, 0x69); - set_2regs(0x0f, 0x25); - break; - case XFER_MW_DMA_1: - set_2regs(0x0e, 0x6b); - set_2regs(0x0f, 0x27); - break; - case XFER_MW_DMA_0: - set_2regs(0x0e, 0xdf); - set_2regs(0x0f, 0x5f); - break; -#else - switch (speed) { -#endif /* CONFIG_BLK_DEV_IDEDMA */ - case XFER_PIO_4: - set_2regs(0x0c, 0x23); - set_2regs(0x0d, 0x09); - set_2regs(0x13, 0x25); - break; - case XFER_PIO_3: - set_2regs(0x0c, 0x27); - set_2regs(0x0d, 0x0d); - set_2regs(0x13, 0x35); - break; - case XFER_PIO_2: - set_2regs(0x0c, 0x23); - set_2regs(0x0d, 0x26); - set_2regs(0x13, 0x64); - break; - case XFER_PIO_1: - set_2regs(0x0c, 0x46); - set_2regs(0x0d, 0x29); - set_2regs(0x13, 0xa4); - break; - case XFER_PIO_0: - set_2regs(0x0c, 0xfb); - set_2regs(0x0d, 0x2b); - set_2regs(0x13, 0xac); - break; - default: - ; +#endif + + for (i = 0 ; i < 2 ; i++) + if (hwif->drives[i].present) + drives[i+j] = &hwif->drives[i]; + + err = ide_config_drive_speed(drive, speed); + + /* For modes < UDMA mode 6 we need only to SET_FEATURE */ + if (speed < XFER_UDMA_6) + return err; + + /* We need to adjust timings to ATA133 clock if ATA133 drives exist */ + for (i = 0 ; i < 4 ; i++) { + if (!drives[i]) + continue; + + /* Primary = 0x01, Secondary = 0x09 */ + indexreg = high_16 + ((i > 1) ? 0x09 : 0x01); + datareg = indexreg + 2; + + /* Master = 0x00, Slave = 0x08 */ + adj = (i % 2) ? 0x08 : 0x00; + + switch (drives[i]->current_speed) { +#ifdef CONFIG_BLK_DEV_IDEDMA + case XFER_UDMA_6: + set_2regs(0x10, 0x1a); + set_2regs(0x11, 0x01); + set_2regs(0x12, 0xcb); + break; + case XFER_UDMA_5: + set_2regs(0x10, 0x1a); + set_2regs(0x11, 0x02); + set_2regs(0x12, 0xcb); + break; + case XFER_UDMA_4: + set_2regs(0x10, 0x1a); + set_2regs(0x11, 0x03); + set_2regs(0x12, 0xcd); + break; + case XFER_UDMA_3: + set_2regs(0x10, 0x1a); + set_2regs(0x11, 0x05); + set_2regs(0x12, 0xcd); + break; + case XFER_UDMA_2: + set_2regs(0x10, 0x2a); + set_2regs(0x11, 0x07); + set_2regs(0x12, 0xcd); + break; + case XFER_UDMA_1: + set_2regs(0x10, 0x3a); + set_2regs(0x11, 0x0a); + set_2regs(0x12, 0xd0); + break; + case XFER_UDMA_0: + set_2regs(0x10, 0x4a); + set_2regs(0x11, 0x0f); + set_2regs(0x12, 0xd5); + break; + case XFER_MW_DMA_2: + set_2regs(0x0e, 0x69); + set_2regs(0x0f, 0x25); + break; + case XFER_MW_DMA_1: + set_2regs(0x0e, 0x6b); + set_2regs(0x0f, 0x27); + break; + case XFER_MW_DMA_0: + set_2regs(0x0e, 0xdf); + set_2regs(0x0f, 0x5f); + break; +#endif + case XFER_PIO_4: + set_2regs(0x0c, 0x23); + set_2regs(0x0d, 0x09); + set_2regs(0x13, 0x25); + break; + case XFER_PIO_3: + set_2regs(0x0c, 0x27); + set_2regs(0x0d, 0x0d); + set_2regs(0x13, 0x35); + break; + case XFER_PIO_2: + set_2regs(0x0c, 0x23); + set_2regs(0x0d, 0x26); + set_2regs(0x13, 0x64); + break; + case XFER_PIO_1: + set_2regs(0x0c, 0x46); + set_2regs(0x0d, 0x29); + set_2regs(0x13, 0xa4); + break; + case XFER_PIO_0: + set_2regs(0x0c, 0xfb); + set_2regs(0x0d, 0x2b); + set_2regs(0x13, 0xac); + break; + default: + ; + } } - return ide_config_drive_speed(drive, speed); + return err; } /* 0 1 2 3 4 5 6 7 8 @@ -475,16 +511,19 @@ static void pdc202xx_udma_start(struct ata_device *drive, struct request *rq) { struct ata_channel *ch = drive->channel; u32 high_16 = pci_resource_start(ch->pci_dev, 4); - unsigned long atapi_reg = high_16 + (ch->unit ? 0x24 : 0x00); + unsigned long atapi_port = high_16 + (ch->unit ? 0x24 : 0x20); + /* Enable ATAPI UDMA port for 48bit data on PDC20265/PDC20267 */ if (drive->addressing) { - unsigned long word_count = 0; - u8 clock = IN_BYTE(high_16 + PDC_CLK); + unsigned long word_count = 0, hankval; + u32 clockreg = high_16 + PDC_CLK; + u8 clock = IN_BYTE(clockreg); - outb(clock|(ch->unit ? 0x08 : 0x02), high_16 + PDC_CLK); + OUT_BYTE(clock | (ch->unit ? 0x08 : 0x02), clockreg); word_count = (rq->nr_sectors << 8); - word_count = (rq_data_dir(rq) == READ) ? word_count | 0x05000000 : word_count | 0x06000000; - outl(word_count, atapi_reg); + hankval = (rq_data_dir(rq) == READ) ? 0x05 << 24 : 0x06 << 24; + hankval |= word_count; + outl(hankval, atapi_port); } /* Note that this is done *after* the cmd has been issued to the drive, @@ -499,14 +538,18 @@ static int pdc202xx_udma_stop(struct ata_device *drive) { struct ata_channel *ch = drive->channel; u32 high_16 = pci_resource_start(ch->pci_dev, 4); - unsigned long atapi_reg = high_16 + (ch->unit ? 0x24 : 0x00); + unsigned long atapi_port = high_16 + (ch->unit ? 0x24 : 0x20); unsigned long dma_base = ch->dma_base; - u8 dma_stat, clock; + u8 dma_stat; + /* Disable ATAPI UDMA port for 48bit data on PDC20265/PDC20267 */ if (drive->addressing) { - outl(0, atapi_reg); /* zero out extra */ - clock = IN_BYTE(high_16 + PDC_CLK); - OUT_BYTE(clock & ~(ch->unit ? 0x08:0x02), high_16 + PDC_CLK); + u32 clockreg = high_16 + PDC_CLK; + u8 clock; + + outl(0, atapi_port); /* zero out extra */ + clock = IN_BYTE(clockreg); + OUT_BYTE(clock & ~(ch->unit ? 0x08 : 0x02), clockreg); } outb(inb(dma_base)&~1, dma_base); /* stop DMA */ @@ -527,21 +570,21 @@ static void pdc202xx_bug(struct ata_device *drive) #endif -static void pdc202xx_new_reset(struct ata_device *drive) +/* FIXME: use generic ata_reset() --bzolnier */ +static void pdc202xx_reset(struct ata_device *drive) { - ata_reset(drive->channel); - mdelay(1000); - ata_irq_enable(drive, 1); - mdelay(1000); + outb(0x04, drive->channel->io_ports[IDE_CONTROL_OFFSET]); + udelay(10); + outb(0x00, drive->channel->io_ports[IDE_CONTROL_OFFSET]); printk(KERN_INFO "PDC202XX: %s channel reset.\n", - drive->channel->unit ? "Secondary" : "Primary"); + drive->channel->unit ? "Secondary" : "Primary"); } /* * software host reset * * BIOS will set UDMA timing on if the drive supports it. - * The user may then want to turn it off. A bug is that + * The user may then want to turn it off. A bug is * that device cannot handle a downgrade in timing from * UDMA to DMA. Disk accesses after issuing a set * feature command will result in errors. @@ -549,6 +592,7 @@ static void pdc202xx_new_reset(struct ata_device *drive) * A software reset leaves the timing registers intact, * but resets the drives on both channels. */ +#if 0 static void pdc202xx_reset_host(struct pci_dev *dev) { u32 high_16 = pci_resource_start(dev, 4); @@ -566,17 +610,24 @@ void pdc202xx_reset(struct ata_device *drive) printk(KERN_INFO "%s: channel needs reset.\n", ch->name); pdc202xx_reset_host(ch->pci_dev); } +#endif static unsigned int __init pdc202xx_init_chipset(struct pci_dev *dev) { u32 high_16 = pci_resource_start(dev, 4); - u8 burst = IN_BYTE(high_16 + PDC_UDMA); + u32 burstreg = high_16 + PDC_UDMA; + u8 burst = IN_BYTE(burstreg); + + set_reg_and_wait(burst | 0x10, burstreg, 100); + /* FIXME: 2 seconds ?! */ + set_reg_and_wait(burst & ~0x10, burstreg, 2000); if (dev->resource[PCI_ROM_RESOURCE].start) { pci_write_config_dword(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE); printk(KERN_INFO "%s: ROM enabled at 0x%08lx\n", dev->name, dev->resource[PCI_ROM_RESOURCE].start); } +#if 0 switch (dev->device) { case PCI_DEVICE_ID_PROMISE_20267: case PCI_DEVICE_ID_PROMISE_20265: @@ -584,8 +635,6 @@ static unsigned int __init pdc202xx_init_chipset(struct pci_dev *dev) pdc202xx_reset_host(dev); break; default: - /* FIXME: only checked for 20246 - is this right?, - if it is needed it should go to ide-pci --bkz */ if ((dev->class >> 8) != PCI_CLASS_STORAGE_IDE) { byte irq = 0, irq2 = 0; pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq); @@ -597,11 +646,13 @@ static unsigned int __init pdc202xx_init_chipset(struct pci_dev *dev) } break; } +#endif #ifdef CONFIG_PDC202XX_BURST if (!(burst & 1)) { printk(KERN_INFO "%s: forcing (U)DMA BURST.\n", dev->name); - OUT_BYTE(burst | 1, high_16 + PDC_UDMA); + OUT_BYTE(burst | 1, burstreg); + burst = IN_BYTE(burstreg); } #endif printk(KERN_INFO "%s: (U)DMA BURST %sabled, " @@ -613,6 +664,7 @@ static unsigned int __init pdc202xx_init_chipset(struct pci_dev *dev) return dev->irq; } +#if 0 /* chipsets newer then 20267 */ static unsigned int __init pdc202xx_tx_init_chipset(struct pci_dev *dev) { @@ -622,6 +674,7 @@ static unsigned int __init pdc202xx_tx_init_chipset(struct pci_dev *dev) } return dev->irq; } +#endif static unsigned int __init pdc202xx_ata66_check(struct ata_channel *ch) { @@ -642,17 +695,18 @@ static void __init ide_init_pdc202xx(struct ata_channel *hwif) { hwif->tuneproc = &pdc202xx_tune_drive; hwif->quirkproc = &check_in_drive_lists; + hwif->resetproc = &pdc202xx_reset; switch(hwif->pci_dev->device) { - case PCI_DEVICE_ID_PROMISE_20275: case PCI_DEVICE_ID_PROMISE_20276: + case PCI_DEVICE_ID_PROMISE_20275: + case PCI_DEVICE_ID_PROMISE_20271: case PCI_DEVICE_ID_PROMISE_20269: case PCI_DEVICE_ID_PROMISE_20268: case PCI_DEVICE_ID_PROMISE_20268R: hwif->udma_four = pdc202xx_tx_ata66_check(hwif); hwif->speedproc = &pdc202xx_new_tune_chipset; - hwif->resetproc = &pdc202xx_new_reset; #ifdef CONFIG_BLK_DEV_IDEDMA if (hwif->dma_base) hwif->udma_setup = pdc202xx_tx_udma_setup; @@ -660,10 +714,6 @@ static void __init ide_init_pdc202xx(struct ata_channel *hwif) break; case PCI_DEVICE_ID_PROMISE_20267: case PCI_DEVICE_ID_PROMISE_20265: - case PCI_DEVICE_ID_PROMISE_20262: - hwif->udma_four = pdc202xx_ata66_check(hwif); - - hwif->resetproc = &pdc202xx_reset; #ifdef CONFIG_BLK_DEV_IDEDMA /* we need special functions for lba48 */ if (hwif->dma_base) { @@ -671,7 +721,10 @@ static void __init ide_init_pdc202xx(struct ata_channel *hwif) hwif->udma_stop = pdc202xx_udma_stop; } #endif - /* FIXME: check whether 20246 works with lba48 --bkz */ + /* PDC20262 doesn't support LBA48 */ + case PCI_DEVICE_ID_PROMISE_20262: + hwif->udma_four = pdc202xx_ata66_check(hwif); + case PCI_DEVICE_ID_PROMISE_20246: #ifdef CONFIG_BLK_DEV_IDEDMA if (hwif->dma_base) @@ -752,7 +805,7 @@ static struct ata_pci_device chipsets[] __initdata = { { vendor: PCI_VENDOR_ID_PROMISE, device: PCI_DEVICE_ID_PROMISE_20268, - init_chipset: pdc202xx_tx_init_chipset, + init_chipset: pdc202xx_init_chipset, init_channel: ide_init_pdc202xx, bootable: OFF_BOARD, flags: ATA_F_IRQ | ATA_F_DMA @@ -764,7 +817,7 @@ static struct ata_pci_device chipsets[] __initdata = { { vendor: PCI_VENDOR_ID_PROMISE, device: PCI_DEVICE_ID_PROMISE_20268R, - init_chipset: pdc202xx_tx_init_chipset, + init_chipset: pdc202xx_init_chipset, init_channel: ide_init_pdc202xx, bootable: OFF_BOARD, flags: ATA_F_IRQ | ATA_F_DMA @@ -772,7 +825,15 @@ static struct ata_pci_device chipsets[] __initdata = { { vendor: PCI_VENDOR_ID_PROMISE, device: PCI_DEVICE_ID_PROMISE_20269, - init_chipset: pdc202xx_tx_init_chipset, + init_chipset: pdc202xx_init_chipset, + init_channel: ide_init_pdc202xx, + bootable: OFF_BOARD, + flags: ATA_F_IRQ | ATA_F_DMA + }, + { + vendor: PCI_VENDOR_ID_PROMISE, + device: PCI_DEVICE_ID_PROMISE_20271, + init_chipset: pdc202xx_init_chipset, init_channel: ide_init_pdc202xx, bootable: OFF_BOARD, flags: ATA_F_IRQ | ATA_F_DMA @@ -780,7 +841,7 @@ static struct ata_pci_device chipsets[] __initdata = { { vendor: PCI_VENDOR_ID_PROMISE, device: PCI_DEVICE_ID_PROMISE_20275, - init_chipset: pdc202xx_tx_init_chipset, + init_chipset: pdc202xx_init_chipset, init_channel: ide_init_pdc202xx, bootable: OFF_BOARD, flags: ATA_F_IRQ | ATA_F_DMA @@ -788,7 +849,7 @@ static struct ata_pci_device chipsets[] __initdata = { { vendor: PCI_VENDOR_ID_PROMISE, device: PCI_DEVICE_ID_PROMISE_20276, - init_chipset: pdc202xx_tx_init_chipset, + init_chipset: pdc202xx_init_chipset, init_channel: ide_init_pdc202xx, bootable: OFF_BOARD, flags: ATA_F_IRQ | ATA_F_DMA diff --git a/drivers/ide/pdc4030.c b/drivers/ide/pdc4030.c index 6a4153e15cee..5fff033d2891 100644 --- a/drivers/ide/pdc4030.c +++ b/drivers/ide/pdc4030.c @@ -415,7 +415,7 @@ read_next: rq->nr_sectors -= nsect; total_remaining = rq->nr_sectors; if ((rq->current_nr_sectors -= nsect) <= 0) - __ata_end_request(drive, rq, 1, 0); + ata_end_request(drive, rq, 1, 0); /* * Now the data has been read in, do the following: @@ -477,7 +477,7 @@ static ide_startstop_t promise_complete_pollfunc(struct ata_device *drive, struc #ifdef DEBUG_WRITE printk(KERN_DEBUG "%s: Write complete - end_request\n", drive->name); #endif - __ata_end_request(drive, rq, 1, rq->nr_sectors); + ata_end_request(drive, rq, 1, rq->nr_sectors); return ATA_OP_FINISHED; } @@ -629,7 +629,7 @@ ide_startstop_t do_pdc4030_io(struct ata_device *drive, struct ata_taskfile *arg /* Check that it's a regular command. If not, bomb out early. */ if (!(rq->flags & REQ_CMD)) { blk_dump_rq_flags(rq, "pdc4030 bad flags"); - __ata_end_request(drive, rq, 0, 0); + ata_end_request(drive, rq, 0, 0); return ATA_OP_FINISHED; } @@ -709,7 +709,7 @@ ide_startstop_t do_pdc4030_io(struct ata_device *drive, struct ata_taskfile *arg default: printk(KERN_ERR "pdc4030: command not READ or WRITE! Huh?\n"); - __ata_end_request(drive, rq, 0, 0); + ata_end_request(drive, rq, 0, 0); return ATA_OP_FINISHED; } } diff --git a/drivers/ide/pdcraid.c b/drivers/ide/pdcraid.c index ac31d2f2c398..c10d82515001 100644 --- a/drivers/ide/pdcraid.c +++ b/drivers/ide/pdcraid.c @@ -12,7 +12,7 @@ Authors: Arjan van de Ven - Based on work done by Søren Schmidt for FreeBSD + Based on work done by Søren Schmidt for FreeBSD */ diff --git a/drivers/ide/probe.c b/drivers/ide/probe.c index e9a62b5d03b4..da683c0783f5 100644 --- a/drivers/ide/probe.c +++ b/drivers/ide/probe.c @@ -97,11 +97,15 @@ int ide_xlate_1024(kdev_t i_rdev, int xparm, int ptheads, const char *msg) } } - /* There used to be code here that assigned drive->id->CHS - to drive->CHS and that to drive->bios_CHS. However, some disks have - id->C/H/S = 4092/16/63 but are larger than 2.1 GB. In such cases - that code was wrong. Moreover, there seems to be no reason to do - any of these things. */ + /* There used to be code here that assigned drive->id->CHS to + * drive->CHS and that to drive->bios_CHS. However, some disks have + * id->C/H/S = 4092/16/63 but are larger than 2.1 GB. In such cases + * that code was wrong. Moreover, there seems to be no reason to do + * any of these things. + * + * Please note that recent RedHat changes to the disk utils are bogous + * and will report spurious errors. + */ /* translate? */ if (drive->forced_geom) @@ -169,8 +173,8 @@ int ide_xlate_1024(kdev_t i_rdev, int xparm, int ptheads, const char *msg) } /* - * hd_driveid data come as little endian, it needs to be converted on big - * endian machines. + * Drive ID data come as little endian, it needs to be converted on big endian + * machines. */ void ata_fix_driveid(struct hd_driveid *id) { @@ -319,11 +323,8 @@ int ide_config_drive_speed(struct ata_device *drive, byte speed) outb(inb(ch->dma_base + 2) & ~(1 << (5 + unit)), ch->dma_base + 2); #endif - /* Don't use ide_wait_cmd here - it will attempt to set_geometry and - * recalibrate, but for some reason these don't work at this point - * (lost interrupt). - * - * Select the drive, and issue the SETFEATURES command + /* + * Select the drive, and issue the SETFEATURES command. */ disable_irq(ch->irq); /* disable_irq_nosync ?? */ udelay(1); @@ -339,7 +340,6 @@ int ide_config_drive_speed(struct ata_device *drive, byte speed) udelay(1); ret = ata_status_poll(drive, 0, BUSY_STAT, WAIT_CMD, NULL); ata_mask(drive); - enable_irq(ch->irq); if (ret != ATA_OP_READY) { @@ -1127,6 +1127,7 @@ static void channel_init(struct ata_channel *ch) gd->sizes = kmalloc(ATA_MINORS * sizeof(int), GFP_KERNEL); if (!gd->sizes) goto err_kmalloc_gd_sizes; + memset(gd->sizes, 0, ATA_MINORS*sizeof(gd->sizes[0])); gd->part = kmalloc(ATA_MINORS * sizeof(struct hd_struct), GFP_KERNEL); if (!gd->part) diff --git a/drivers/ide/tcq.c b/drivers/ide/tcq.c index 3f64394baf09..2d05fd15fb49 100644 --- a/drivers/ide/tcq.c +++ b/drivers/ide/tcq.c @@ -134,7 +134,6 @@ static void tcq_invalidate_queue(struct ata_device *drive) ar->XXX_handler = tcq_nop_handler; ar->command_type = IDE_DRIVE_TASK_NO_DATA; - rq->rq_dev = mk_kdev(drive->channel->major, (drive->select.b.unit)<tag); - __ata_end_request(drive, rq, !dma_stat, rq->nr_sectors); + ata_end_request(drive, rq, !dma_stat, rq->nr_sectors); /* * we completed this command, check if we can service a new command diff --git a/drivers/ide/umc8672.c b/drivers/ide/umc8672.c index 8598b5d01702..2769442f4e33 100644 --- a/drivers/ide/umc8672.c +++ b/drivers/ide/umc8672.c @@ -129,7 +129,7 @@ void __init init_umc8672(void) /* called from ide.c */ __save_flags(flags); /* local CPU only */ __cli(); /* local CPU only */ - if (check_region(0x108, 2)) { + if (!request_region(0x108, 2, "umc8672")) { __restore_flags(flags); printk("\numc8672: PORTS 0x108-0x109 ALREADY IN USE\n"); return; @@ -138,6 +138,7 @@ void __init init_umc8672(void) /* called from ide.c */ if (in_umc (0xd5) != 0xa0) { __restore_flags(flags); /* local CPU only */ + release_region(0x108, 2); printk ("umc8672: not found\n"); return; } @@ -146,7 +147,6 @@ void __init init_umc8672(void) /* called from ide.c */ umc_set_speeds (current_speeds); __restore_flags(flags); /* local CPU only */ - request_region(0x108, 2, "umc8672"); ide_hwifs[0].chipset = ide_umc8672; ide_hwifs[1].chipset = ide_umc8672; ide_hwifs[0].tuneproc = &tune_umc; diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c index 8598f13d0ee3..1f001b4172cc 100644 --- a/drivers/scsi/ide-scsi.c +++ b/drivers/scsi/ide-scsi.c @@ -244,7 +244,7 @@ static int idescsi_end_request(struct ata_device *drive, struct request *rq, int u8 *scsi_buf; if (!(rq->flags & REQ_PC)) { - __ata_end_request(drive, rq, uptodate, 0); + ata_end_request(drive, rq, uptodate, 0); return 0; } @@ -491,14 +491,13 @@ static void idescsi_release(struct inode *inode, struct file *filp, struct ata_d MOD_DEC_USE_COUNT; } +static Scsi_Host_Template template; static int idescsi_cleanup (struct ata_device *drive) { - struct Scsi_Host *host = drive->driver_data; - if (ide_unregister_subdriver (drive)) { return 1; } - scsi_unregister(host); + scsi_unregister_host(&template); return 0; } @@ -801,7 +800,6 @@ static int __init init_idescsi_module(void) static void __exit exit_idescsi_module(void) { unregister_ata_driver(&ata_ops); - scsi_unregister_host(&template); } module_init(init_idescsi_module); diff --git a/include/linux/atapi.h b/include/linux/atapi.h index 0ac305922e3a..806aa4e49146 100644 --- a/include/linux/atapi.h +++ b/include/linux/atapi.h @@ -74,15 +74,6 @@ struct atapi_packet_command { } s; }; -extern void atapi_init_pc(struct atapi_packet_command *pc); - -extern void atapi_discard_data(struct ata_device *, unsigned int); -extern void atapi_write_zeros(struct ata_device *, unsigned int); - -extern void atapi_read(struct ata_device *, u8 *, unsigned int); -extern void atapi_write(struct ata_device *, u8 *, unsigned int); - - /* * ATAPI Status Register. */ @@ -360,3 +351,20 @@ typedef struct atapi_request_sense { u8 sk_specific[2]; /* Sense Key Specific */ u8 pad[2]; /* Padding to 20 bytes */ } atapi_request_sense_result_t; + + +extern void atapi_init_pc(struct atapi_packet_command *pc); + +extern void atapi_discard_data(struct ata_device *, unsigned int); +extern void atapi_write_zeros(struct ata_device *, unsigned int); + +extern void atapi_read(struct ata_device *, u8 *, unsigned int); +extern void atapi_write(struct ata_device *, u8 *, unsigned int); + +typedef enum { + ide_wait, /* insert rq at end of list, and wait for it */ + ide_preempt, /* insert rq in front of current request */ + ide_end /* insert rq at end of list, but don't wait for it */ +} ide_action_t; + +extern int ide_do_drive_cmd(struct ata_device *, struct request *, ide_action_t); diff --git a/include/linux/ide.h b/include/linux/ide.h index 4076310675f8..7b9c5cce01cf 100644 --- a/include/linux/ide.h +++ b/include/linux/ide.h @@ -1,5 +1,6 @@ #ifndef _IDE_H #define _IDE_H + /* * Copyright (C) 1994-2002 Linus Torvalds & authors */ @@ -57,15 +58,14 @@ typedef unsigned char byte; /* used everywhere */ */ #define ERROR_MAX 8 /* Max read/write errors per sector */ #define ERROR_RESET 3 /* Reset controller every 4th retry */ -#define ERROR_RECAL 1 /* Recalibrate every 2nd retry */ /* - * state flags + * State flags. */ #define DMA_PIO_RETRY 1 /* retrying in PIO */ /* - * Definitions for accessing IDE controller registers + * Definitions for accessing IDE controller registers. */ enum { @@ -192,23 +192,21 @@ typedef enum { * Structure to hold all information about the location of this port */ typedef struct hw_regs_s { - ide_ioreg_t io_ports[IDE_NR_PORTS]; /* task file registers */ - int irq; /* our irq number */ - int dma; /* our dma entry */ - ide_ack_intr_t *ack_intr; /* acknowledge interrupt */ + ide_ioreg_t io_ports[IDE_NR_PORTS]; /* task file registers */ + int irq; /* our irq number */ + int dma; /* our dma entry */ + int (*ack_intr)(struct ata_channel *); /* acknowledge interrupt */ hwif_chipset_t chipset; } hw_regs_t; /* * Set up hw_regs_t structure before calling ide_register_hw (optional) */ -void ide_setup_ports(hw_regs_t *hw, - ide_ioreg_t base, - int *offsets, - ide_ioreg_t ctrl, - ide_ioreg_t intr, - ide_ack_intr_t *ack_intr, - int irq); +extern void ide_setup_ports(hw_regs_t *hw, + ide_ioreg_t base, int *offsets, + ide_ioreg_t ctrl, ide_ioreg_t intr, + int (*ack_intr)(struct ata_channel *), + int irq); #include @@ -282,14 +280,10 @@ struct ata_device { unsigned int usage; /* current "open()" count for drive */ char type; /* distingiush different devices: disk, cdrom, tape, floppy, ... */ - /* NOTE: If we had proper separation between channel and host chip, we - * could move this to the channel and many sync problems would - * magically just go away. - */ - request_queue_t queue; /* per device request queue */ + request_queue_t queue; /* per device request queue */ struct request *rq; /* current request */ - unsigned long sleep; /* sleep until this time */ + unsigned long sleep; /* sleep until this time */ byte retry_pio; /* retrying dma capable host in pio */ byte state; /* retry state */ @@ -341,6 +335,7 @@ struct ata_device { void *driver_data; /* extra driver data */ devfs_handle_t de; /* directory for device */ + char driver_req[10]; /* requests specific driver */ int last_lun; /* last logical unit */ @@ -392,6 +387,7 @@ enum { enum { IDE_BUSY, /* awaiting an interrupt */ IDE_SLEEP, + IDE_PIO, /* PIO in progress */ IDE_DMA /* DMA in progress */ }; @@ -404,11 +400,15 @@ struct ata_channel { */ spinlock_t *lock; unsigned long *active; /* active processing request */ - ide_startstop_t (*handler)(struct ata_device *, struct request *); /* irq handler, if active */ + + /* FIXME: Only still used in PDC4030. Localize this code there by + * replacing with busy waits. + */ struct timer_list timer; /* failsafe timer */ ide_startstop_t (*expiry)(struct ata_device *, struct request *, unsigned long *); /* irq handler, if active */ unsigned long poll_timeout; /* timeout value during polled operations */ + struct ata_device *drive; /* last serviced drive */ @@ -508,8 +508,6 @@ struct ata_channel { extern int ide_register_hw(hw_regs_t *hw); extern void ide_unregister(struct ata_channel *); -struct ata_taskfile; - #define IDE_MAX_TAG 32 #ifdef CONFIG_BLK_DEV_IDE_TCQ @@ -605,8 +603,7 @@ extern int noautodma; #define DEVICE_NR(device) (minor(device) >> PARTN_BITS) #include -extern int __ata_end_request(struct ata_device *, struct request *, int, unsigned int); - +extern int ata_end_request(struct ata_device *, struct request *, int, unsigned int); extern void ata_set_handler(struct ata_device *drive, ata_handler_t handler, unsigned long timeout, ata_expiry_t expiry); @@ -626,22 +623,11 @@ int ide_xlate_1024(kdev_t, int, int, const char *); */ struct ata_device *get_info_ptr(kdev_t i_rdev); -/* - * "action" parameter type for ide_do_drive_cmd() below. - */ -typedef enum { - ide_wait, /* insert rq at end of list, and wait for it */ - ide_preempt, /* insert rq in front of current request */ - ide_end /* insert rq at end of list, but don't wait for it */ -} ide_action_t; - /* * temporarily mapping a (possible) highmem bio for PIO transfer */ #define ide_rq_offset(rq) (((rq)->hard_cur_sectors - (rq)->current_nr_sectors) << 9) -extern int ide_do_drive_cmd(struct ata_device *, struct request *, ide_action_t); - struct ata_taskfile { struct hd_drive_task_hdr taskfile; struct hd_drive_task_hdr hobfile; @@ -654,7 +640,6 @@ extern void ata_read(struct ata_device *, void *, unsigned int); extern void ata_write(struct ata_device *, void *, unsigned int); extern int ide_raw_taskfile(struct ata_device *, struct ata_taskfile *, char *); -extern void ide_fix_driveid(struct hd_driveid *id); extern int ide_config_drive_speed(struct ata_device *, byte); extern byte eighty_ninty_three(struct ata_device *); @@ -803,13 +788,12 @@ extern spinlock_t ide_lock; #define DRIVE_LOCK(drive) ((drive)->queue.queue_lock) -extern int drive_is_ready(struct ata_device *drive); - /* Low level device access functions. */ extern void ata_select(struct ata_device *, unsigned long); extern void ata_mask(struct ata_device *); extern int ata_status(struct ata_device *, u8, u8); +extern int ata_status_irq(struct ata_device *drive); extern int ata_status_poll( struct ata_device *, u8, u8, unsigned long, struct request *rq); diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 6758bf742e0c..c1f391bf8f62 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -610,6 +610,7 @@ #define PCI_DEVICE_ID_PROMISE_20268 0x4d68 #define PCI_DEVICE_ID_PROMISE_20268R 0x6268 #define PCI_DEVICE_ID_PROMISE_20269 0x4d69 +#define PCI_DEVICE_ID_PROMISE_20271 0x6269 #define PCI_DEVICE_ID_PROMISE_20275 0x1275 #define PCI_DEVICE_ID_PROMISE_20276 0x5275 #define PCI_DEVICE_ID_PROMISE_5300 0x5300 -- cgit v1.2.3