cregit-Linux how code gets into the kernel

Release 4.7 drivers/block/hd.c

Directory: drivers/block
/*
 *  Copyright (C) 1991, 1992  Linus Torvalds
 *
 * This is the low-level hd interrupt support. It traverses the
 * request-list, using interrupts to jump between functions. As
 * all the functions are called within interrupts, we may not
 * sleep. Special care is recommended.
 *
 *  modified by Drew Eckhardt to check nr of hd's from the CMOS.
 *
 *  Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
 *  in the early extended-partition checks and added DM partitions
 *
 *  IRQ-unmask, drive-id, multiple-mode, support for ">16 heads",
 *  and general streamlining by Mark Lord.
 *
 *  Removed 99% of above. Use Mark's ide driver for those options.
 *  This is now a lightweight ST-506 driver. (Paul Gortmaker)
 *
 *  Modified 1995 Russell King for ARM processor.
 *
 *  Bugfix: max_sectors must be <= 255 or the wheels tend to come
 *  off in a hurry once you queue things up - Paul G. 02/2001
 */

/* Uncomment the following if you want verbose error reports. */
/* #define VERBOSE_ERRORS */

#include <linux/blkdev.h>
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/interrupt.h>
#include <linux/timer.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/genhd.h>
#include <linux/string.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/blkpg.h>
#include <linux/ata.h>
#include <linux/hdreg.h>


#define HD_IRQ 14


#define REALLY_SLOW_IO
#include <asm/io.h>
#include <asm/uaccess.h>

#ifdef __arm__

#undef  HD_IRQ
#endif
#include <asm/irq.h>
#ifdef __arm__

#define HD_IRQ IRQ_HARDDISK
#endif

/* Hd controller regster ports */


#define HD_DATA		0x1f0		
/* _CTL when writing */

#define HD_ERROR	0x1f1		
/* see err-bits */

#define HD_NSECTOR	0x1f2		
/* nr of sectors to read/write */

#define HD_SECTOR	0x1f3		
/* starting sector */

#define HD_LCYL		0x1f4		
/* starting cylinder */

#define HD_HCYL		0x1f5		
/* high byte of starting cyl */

#define HD_CURRENT	0x1f6		
/* 101dhhhh , d=drive, hhhh=head */

#define HD_STATUS	0x1f7		
/* see status-bits */

#define HD_FEATURE	HD_ERROR	
/* same io address, read=error, write=feature */

#define HD_PRECOMP	HD_FEATURE	
/* obsolete use of this port - predates IDE */

#define HD_COMMAND	HD_STATUS	
/* same io address, read=status, write=cmd */


#define HD_CMD		0x3f6		
/* used for resets */

#define HD_ALTSTATUS	0x3f6		
/* same as HD_STATUS but doesn't clear irq */

/* Bits of HD_STATUS */

#define ERR_STAT		0x01

#define INDEX_STAT		0x02

#define ECC_STAT		0x04	
/* Corrected error */

#define DRQ_STAT		0x08

#define SEEK_STAT		0x10

#define SERVICE_STAT		SEEK_STAT

#define WRERR_STAT		0x20

#define READY_STAT		0x40

#define BUSY_STAT		0x80

/* Bits for HD_ERROR */

#define MARK_ERR		0x01	
/* Bad address mark */

#define TRK0_ERR		0x02	
/* couldn't find track 0 */

#define ABRT_ERR		0x04	
/* Command aborted */

#define MCR_ERR			0x08	
/* media change request */

#define ID_ERR			0x10	
/* ID field not found */

#define MC_ERR			0x20	
/* media changed */

#define ECC_ERR			0x40	
/* Uncorrectable ECC error */

#define BBD_ERR			0x80	
/* pre-EIDE meaning:  block marked bad */

#define ICRC_ERR		0x80	
/* new meaning:  CRC error during transfer */

static DEFINE_SPINLOCK(hd_lock);

static struct request_queue *hd_queue;

static struct request *hd_req;


#define TIMEOUT_VALUE	(6*HZ)

#define	HD_DELAY	0


#define MAX_ERRORS     16	
/* Max read/write errors/sector */

#define RESET_FREQ      8	
/* Reset controller every 8th retry */

#define RECAL_FREQ      4	
/* Recalibrate every 4th retry */

#define MAX_HD		2


#define STAT_OK		(READY_STAT|SEEK_STAT)

#define OK_STATUS(s)	(((s)&(STAT_OK|(BUSY_STAT|WRERR_STAT|ERR_STAT)))==STAT_OK)

static void recal_intr(void);
static void bad_rw_intr(void);


static int reset;

static int hd_error;

/*
 *  This struct defines the HD's and their types.
 */

struct hd_i_struct {
	





unsigned int head, sect, cyl, wpcom, lzone, ctl;
	
int unit;
	
int recalibrate;
	
int special_op;
};

#ifdef HD_TYPE

static struct hd_i_struct hd_info[] = { HD_TYPE };

static int NR_HD = ARRAY_SIZE(hd_info);
#else

static struct hd_i_struct hd_info[MAX_HD];

static int NR_HD;
#endif


static struct gendisk *hd_gendisk[MAX_HD];


static struct timer_list device_timer;


#define TIMEOUT_VALUE (6*HZ)


#define SET_TIMER							\
	do {                                                            \
                mod_timer(&device_timer, jiffies + TIMEOUT_VALUE);      \
        } while (0)


static void (*do_hd)(void) = NULL;

#define SET_HANDLER(x) \
if ((do_hd = (x)) != NULL) \
        SET_TIMER; \
else \
        del_timer(&device_timer);


#if (HD_DELAY > 0)

#include <linux/i8253.h>


unsigned long last_req;


unsigned long read_timer(void) { unsigned long t, flags; int i; raw_spin_lock_irqsave(&i8253_lock, flags); t = jiffies * 11932; outb_p(0, 0x43); i = inb_p(0x40); i |= inb(0x40) << 8; raw_spin_unlock_irqrestore(&i8253_lock, flags); return(t - i); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git6188.41%466.67%
martin daleckimartin dalecki68.70%116.67%
thomas gleixnerthomas gleixner22.90%116.67%
Total69100.00%6100.00%

#endif
static void __init hd_setup(char *str, int *ints) { int hdind = 0; if (ints[0] != 3) return; if (hd_info[0].head != 0) hdind = 1; hd_info[hdind].head = ints[2]; hd_info[hdind].sect = ints[3]; hd_info[hdind].cyl = ints[1]; hd_info[hdind].wpcom = 0; hd_info[hdind].lzone = ints[1]; hd_info[hdind].ctl = (ints[2] > 8 ? 8 : 0); NR_HD = hdind+1; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git12799.22%480.00%
bartlomiej zolnierkiewiczbartlomiej zolnierkiewicz10.78%120.00%
Total128100.00%5100.00%


static bool hd_end_request(int err, unsigned int bytes) { if (__blk_end_request(hd_req, err, bytes)) return true; hd_req = NULL; return false; }

Contributors

PersonTokensPropCommitsCommitProp
tejun heotejun heo34100.00%1100.00%
Total34100.00%1100.00%


static bool hd_end_request_cur(int err) { return hd_end_request(err, blk_rq_cur_bytes(hd_req)); }

Contributors

PersonTokensPropCommitsCommitProp
tejun heotejun heo20100.00%1100.00%
Total20100.00%1100.00%


static void dump_status(const char *msg, unsigned int stat) { char *name = "hd?"; if (hd_req) name = hd_req->rq_disk->disk_name; #ifdef VERBOSE_ERRORS printk("%s: %s: status=0x%02x { ", name, msg, stat & 0xff); if (stat & BUSY_STAT) printk("Busy "); if (stat & READY_STAT) printk("DriveReady "); if (stat & WRERR_STAT) printk("WriteFault "); if (stat & SEEK_STAT) printk("SeekComplete "); if (stat & DRQ_STAT) printk("DataRequest "); if (stat & ECC_STAT) printk("CorrectedError "); if (stat & INDEX_STAT) printk("Index "); if (stat & ERR_STAT) printk("Error "); printk("}\n"); if ((stat & ERR_STAT) == 0) { hd_error = 0; } else { hd_error = inb(HD_ERROR); printk("%s: %s: error=0x%02x { ", name, msg, hd_error & 0xff); if (hd_error & BBD_ERR) printk("BadSector "); if (hd_error & ECC_ERR) printk("UncorrectableError "); if (hd_error & ID_ERR) printk("SectorIdNotFound "); if (hd_error & ABRT_ERR) printk("DriveStatusError "); if (hd_error & TRK0_ERR) printk("TrackZeroNotFound "); if (hd_error & MARK_ERR) printk("AddrMarkNotFound "); printk("}"); if (hd_error & (BBD_ERR|ECC_ERR|ID_ERR|MARK_ERR)) { printk(", CHS=%d/%d/%d", (inb(HD_HCYL)<<8) + inb(HD_LCYL), inb(HD_CURRENT) & 0xf, inb(HD_SECTOR)); if (hd_req) printk(", sector=%ld", blk_rq_pos(hd_req)); } printk("\n"); } #else printk("%s: %s: status=0x%02x.\n", name, msg, stat & 0xff); if ((stat & ERR_STAT) == 0) { hd_error = 0; } else { hd_error = inb(HD_ERROR); printk("%s: %s: error=0x%02x.\n", name, msg, hd_error & 0xff); } #endif }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git34792.78%457.14%
al viroal viro205.35%114.29%
tejun heotejun heo71.87%228.57%
Total374100.00%7100.00%


static void check_status(void) { int i = inb_p(HD_STATUS); if (!OK_STATUS(i)) { dump_status("check_status", i); bad_rw_intr(); } }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git3597.22%583.33%
bartlomiej zolnierkiewiczbartlomiej zolnierkiewicz12.78%116.67%
Total36100.00%6100.00%


static int controller_busy(void) { int retries = 100000; unsigned char status; do { status = inb_p(HD_STATUS); } while ((status & BUSY_STAT) && --retries); return status; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git42100.00%2100.00%
Total42100.00%2100.00%


static int status_ok(void) { unsigned char status = inb_p(HD_STATUS); if (status & BUSY_STAT) return 1; /* Ancient, but does it make sense??? */ if (status & WRERR_STAT) return 0; if (!(status & READY_STAT)) return 0; if (!(status & SEEK_STAT)) return 0; return 1; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git63100.00%3100.00%
Total63100.00%3100.00%


static int controller_ready(unsigned int drive, unsigned int head) { int retry = 100; do { if (controller_busy() & BUSY_STAT) return 0; outb_p(0xA0 | (drive<<4) | head, HD_CURRENT); if (status_ok()) return 1; } while (--retry); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git64100.00%3100.00%
Total64100.00%3100.00%


static void hd_out(struct hd_i_struct *disk, unsigned int nsect, unsigned int sect, unsigned int head, unsigned int cyl, unsigned int cmd, void (*intr_addr)(void)) { unsigned short port; #if (HD_DELAY > 0) while (read_timer() - last_req < HD_DELAY) /* nothing */; #endif if (reset) return; if (!controller_ready(disk->unit, head)) { reset = 1; return; } SET_HANDLER(intr_addr); outb_p(disk->ctl, HD_CMD); port = HD_DATA; outb_p(disk->wpcom >> 2, ++port); outb_p(nsect, ++port); outb_p(sect, ++port); outb_p(cyl, ++port); outb_p(cyl >> 8, ++port); outb_p(0xA0 | (disk->unit << 4) | head, ++port); outb_p(cmd, ++port); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git16391.57%675.00%
al viroal viro147.87%112.50%
martin daleckimartin dalecki10.56%112.50%
Total178100.00%8100.00%

static void hd_request (void);
static int drive_busy(void) { unsigned int i; unsigned char c; for (i = 0; i < 500000 ; i++) { c = inb_p(HD_STATUS); if ((c & (BUSY_STAT | READY_STAT | SEEK_STAT)) == STAT_OK) return 0; } dump_status("reset timed out", c); return 1; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git67100.00%7100.00%
Total67100.00%7100.00%


static void reset_controller(void) { int i; outb_p(4, HD_CMD); for (i = 0; i < 1000; i++) barrier(); outb_p(hd_info[0].ctl & 0x0f, HD_CMD); for (i = 0; i < 1000; i++) barrier(); if (drive_busy()) printk("hd: controller still busy\n"); else if ((hd_error = inb(HD_ERROR)) != 1) printk("hd: controller reset failed: %02x\n", hd_error); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git95100.00%5100.00%
Total95100.00%5100.00%


static void reset_hd(void) { static int i; repeat: if (reset) { reset = 0; i = -1; reset_controller(); } else { check_status(); if (reset) goto repeat; } if (++i < NR_HD) { struct hd_i_struct *disk = &hd_info[i]; disk->special_op = disk->recalibrate = 1; hd_out(disk, disk->sect, disk->sect, disk->head-1, disk->cyl, ATA_CMD_INIT_DEV_PARAMS, &reset_hd); if (reset) goto repeat; } else hd_request(); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git9179.82%360.00%
al viroal viro2219.30%120.00%
bartlomiej zolnierkiewiczbartlomiej zolnierkiewicz10.88%120.00%
Total114100.00%5100.00%

/* * Ok, don't know what to do with the unexpected interrupts: on some machines * doing a reset and a retry seems to result in an eternal loop. Right now I * ignore it, and just set the timeout. * * On laptops (and "green" PCs), an unexpected interrupt occurs whenever the * drive enters "idle", "standby", or "sleep" mode, so if the status looks * "good", we just ignore the interrupt completely. */
static void unexpected_hd_interrupt(void) { unsigned int stat = inb_p(HD_STATUS); if (stat & (BUSY_STAT|DRQ_STAT|ECC_STAT|ERR_STAT)) { dump_status("unexpected interrupt", stat); SET_TIMER; } }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git4197.62%583.33%
bartlomiej zolnierkiewiczbartlomiej zolnierkiewicz12.38%116.67%
Total42100.00%6100.00%

/* * bad_rw_intr() now tries to be a bit smarter and does things * according to the error returned by the controller. * -Mika Liljeberg (liljeber@cs.Helsinki.FI) */
static void bad_rw_intr(void) { struct request *req = hd_req; if (req != NULL) { struct hd_i_struct *disk = req->rq_disk->private_data; if (++req->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) { hd_end_request_cur(-EIO); disk->special_op = disk->recalibrate = 1; } else if (req->errors % RESET_FREQ == 0) reset = 1; else if ((hd_error & TRK0_ERR) || req->errors % RECAL_FREQ == 0) disk->special_op = disk->recalibrate = 1; /* Otherwise just retry */ } }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git7164.55%555.56%
al viroal viro2825.45%111.11%
jens axboejens axboe76.36%111.11%
tejun heotejun heo43.64%222.22%
Total110100.00%9100.00%


static inline int wait_DRQ(void) { int retries; int stat; for (retries = 0; retries < 100000; retries++) { stat = inb_p(HD_STATUS); if (stat & DRQ_STAT) return 0; } dump_status("wait_DRQ", stat); return -1; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git3866.67%375.00%
andrew mortonandrew morton1933.33%125.00%
Total57100.00%4100.00%


static void read_intr(void) { struct request *req; int i, retries = 100000; do { i = (unsigned) inb_p(HD_STATUS); if (i & BUSY_STAT) continue; if (!OK_STATUS(i)) break; if (i & DRQ_STAT) goto ok_to_read; } while (--retries > 0); dump_status("read_intr", i); bad_rw_intr(); hd_request(); return; ok_to_read: req = hd_req; insw(HD_DATA, bio_data(req->bio), 256); #ifdef DEBUG printk("%s: read: sector %ld, remaining = %u, buffer=%p\n", req->rq_disk->disk_name, blk_rq_pos(req) + 1, blk_rq_sectors(req) - 1, bio_data(req->bio)+512); #endif if (hd_end_request(0, 512)) { SET_HANDLER(&read_intr); return; } (void) inb_p(HD_STATUS); #if (HD_DELAY > 0) last_req = read_timer(); #endif hd_request(); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git13875.82%1157.89%
al viroal viro179.34%15.26%
tejun heotejun heo168.79%421.05%
jens axboejens axboe84.40%15.26%
nicolas kaisernicolas kaiser21.10%15.26%
martin daleckimartin dalecki10.55%15.26%
Total182100.00%19100.00%


static void write_intr(void) { struct request *req = hd_req; int i; int retries = 100000; do { i = (unsigned) inb_p(HD_STATUS); if (i & BUSY_STAT) continue; if (!OK_STATUS(i)) break; if ((blk_rq_sectors(req) <= 1) || (i & DRQ_STAT)) goto ok_to_write; } while (--retries > 0); dump_status("write_intr", i); bad_rw_intr(); hd_request(); return; ok_to_write: if (hd_end_request(0, 512)) { SET_HANDLER(&write_intr); outsw(HD_DATA, bio_data(req->bio), 256); return; } #if (HD_DELAY > 0) last_req = read_timer(); #endif hd_request(); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git12284.14%850.00%
tejun heotejun heo96.21%425.00%
al viroal viro85.52%16.25%
jens axboejens axboe42.76%16.25%
nicolas kaisernicolas kaiser10.69%16.25%
martin daleckimartin dalecki10.69%16.25%
Total145100.00%16100.00%


static void recal_intr(void) { check_status(); #if (HD_DELAY > 0) last_req = read_timer(); #endif hd_request(); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git28100.00%4100.00%
Total28100.00%4100.00%

/* * This is another of the error-routines I don't know what to do with. The * best idea seems to just set reset, and start all over again. */
static void hd_times_out(unsigned long dummy) { char *name; do_hd = NULL; if (!hd_req) return; spin_lock_irq(hd_queue->queue_lock); reset = 1; name = hd_req->rq_disk->disk_name; printk("%s: timeout\n", name); if (++hd_req->errors >= MAX_ERRORS) { #ifdef DEBUG printk("%s: too many errors\n", name); #endif hd_end_request_cur(-EIO); } hd_request(); spin_unlock_irq(hd_queue->queue_lock); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git6269.66%650.00%
tejun heotejun heo1415.73%325.00%
al viroal viro1213.48%216.67%
jens axboejens axboe11.12%18.33%
Total89100.00%12100.00%


static int do_special_op(struct hd_i_struct *disk, struct request *req) { if (disk->recalibrate) { disk->recalibrate = 0; hd_out(disk, disk->sect, 0, 0, 0, ATA_CMD_RESTORE, &recal_intr); return reset; } if (disk->head > 16) { printk("%s: cannot handle device with more than 16 heads - giving up\n", req->rq_disk->disk_name); hd_end_request_cur(-EIO); } disk->special_op = 0; return 1; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git5865.17%758.33%
al viroal viro2629.21%18.33%
tejun heotejun heo33.37%216.67%
bartlomiej zolnierkiewiczbartlomiej zolnierkiewicz22.25%216.67%
Total89100.00%12100.00%

/* * The driver enables interrupts as much as possible. In order to do this, * (a) the device-interrupt is disabled before entering hd_request(), * and (b) the timeout-interrupt is disabled before the sti(). * * Interrupts are still masked (by default) whenever we are exchanging * data/cmds with a drive, because some drives seem to have very poor * tolerance for latency during I/O. The IDE driver has support to unmask * interrupts for non-broken hardware, so use that driver if required. */
static void hd_request(void) { unsigned int block, nsect, sec, track, head, cyl; struct hd_i_struct *disk; struct request *req; if (do_hd) return; repeat: del_timer(&device_timer); if (!hd_req) { hd_req = blk_fetch_request(hd_queue); if (!hd_req) { do_hd = NULL; return; } } req = hd_req; if (reset) { reset_hd(); return; } disk = req->rq_disk->private_data; block = blk_rq_pos(req); nsect = blk_rq_sectors(req); if (block >= get_capacity(req->rq_disk) || ((block+nsect) > get_capacity(req->rq_disk))) { printk("%s: bad access: block=%d, count=%d\n", req->rq_disk->disk_name, block, nsect); hd_end_request_cur(-EIO); goto repeat; } if (disk->special_op) { if (do_special_op(disk, req)) goto repeat; return; } sec = block % disk->sect + 1; track = block / disk->sect; head = track % disk->head; cyl = track / disk->head; #ifdef DEBUG printk("%s: %sing: CHS=%d/%d/%d, sectors=%d, buffer=%p\n", req->rq_disk->disk_name, req_data_dir(req) == READ ? "read" : "writ", cyl, head, sec, nsect, bio_data(req->bio)); #endif if (req->cmd_type == REQ_TYPE_FS) { switch (rq_data_dir(req)) { case READ: hd_out(disk, nsect, sec, head, cyl, ATA_CMD_PIO_READ, &read_intr); if (reset) goto repeat; break; case WRITE: hd_out(disk, nsect, sec, head, cyl, ATA_CMD_PIO_WRITE, &write_intr); if (reset) goto repeat; if (wait_DRQ()) { bad_rw_intr(); goto repeat; } outsw(HD_DATA, bio_data(req->bio), 256); break; default: printk("unknown hd-command\n"); hd_end_request_cur(-EIO); break; } } }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git23061.66%1142.31%
al viroal viro6517.43%415.38%
tejun heotejun heo297.77%415.38%
linus torvaldslinus torvalds236.17%13.85%
jens axboejens axboe112.95%27.69%
martin daleckimartin dalecki61.61%13.85%
christoph hellwigchristoph hellwig41.07%13.85%
boaz harroshboaz harrosh30.80%13.85%
bartlomiej zolnierkiewiczbartlomiej zolnierkiewicz20.54%13.85%
Total373100.00%26100.00%


static void do_hd_request(struct request_queue *q) { hd_request(); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git1285.71%375.00%
jens axboejens axboe214.29%125.00%
Total14100.00%4100.00%


static int hd_getgeo(struct block_device *bdev, struct hd_geometry *geo) { struct hd_i_struct *disk = bdev->bd_disk->private_data; geo->heads = disk->head; geo->sectors = disk->sect; geo->cylinders = disk->cyl; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git2750.00%675.00%
al viroal viro1527.78%112.50%
christoph hellwigchristoph hellwig1222.22%112.50%
Total54100.00%8100.00%

/* * Releasing a block device means we sync() it, so that it can safely * be forgotten about... */
static irqreturn_t hd_interrupt(int irq, void *dev_id) { void (*handler)(void) = do_hd; spin_lock(hd_queue->queue_lock); do_hd = NULL; del_timer(&device_timer); if (!handler) handler = unexpected_hd_interrupt; handler(); spin_unlock(hd_queue->queue_lock); return IRQ_HANDLED; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git4469.84%457.14%
tejun heotejun heo1320.63%114.29%
andrew mortonandrew morton46.35%114.29%
al viroal viro23.17%114.29%
Total63100.00%7100.00%

static const struct block_device_operations hd_fops = { .getgeo = hd_getgeo, };
static int __init hd_init(void) { int drive; if (register_blkdev(HD_MAJOR, "hd")) return -1; hd_queue = blk_init_queue(do_hd_request, &hd_lock); if (!hd_queue) { unregister_blkdev(HD_MAJOR, "hd"); return -ENOMEM; } blk_queue_max_hw_sectors(hd_queue, 255); init_timer(&device_timer); device_timer.function = hd_times_out; blk_queue_logical_block_size(hd_queue, 512); if (!NR_HD) { /* * We don't know anything about the drive. This means * that you *MUST* specify the drive parameters to the * kernel yourself. * * If we were on an i386, we used to read this info from * the BIOS or CMOS. This doesn't work all that well, * since this assumes that this is a primary or secondary * drive, and if we're using this legacy driver, it's * probably an auxiliary controller added to recover * legacy data off an ST-506 drive. Either way, it's * definitely safest to have the user explicitly specify * the information. */ printk("hd: no drives specified - use hd=cyl,head,sectors" " on kernel command line\n"); goto out; } for (drive = 0 ; drive < NR_HD ; drive++) { struct gendisk *disk = alloc_disk(64); struct hd_i_struct *p = &hd_info[drive]; if (!disk) goto Enomem; disk->major = HD_MAJOR; disk->first_minor = drive << 6; disk->fops = &hd_fops; sprintf(disk->disk_name, "hd%c", 'a'+drive); disk->private_data = p; set_capacity(disk, p->head * p->sect * p->cyl); disk->queue = hd_queue; p->unit = drive; hd_gendisk[drive] = disk; printk("%s: %luMB, CHS=%d/%d/%d\n", disk->disk_name, (unsigned long)get_capacity(disk)/2048, p->cyl, p->head, p->sect); } if (request_irq(HD_IRQ, hd_interrupt, 0, "hd", NULL)) { printk("hd: unable to get IRQ%d for the hard disk driver\n", HD_IRQ); goto out1; } if (!request_region(HD_DATA, 8, "hd")) { printk(KERN_WARNING "hd: port 0x%x busy\n", HD_DATA); goto out2; } if (!request_region(HD_CMD, 1, "hd(cmd)")) { printk(KERN_WARNING "hd: port 0x%x busy\n", HD_CMD); goto out3; } /* Let them fly */ for (drive = 0; drive < NR_HD; drive++) add_disk(hd_gendisk[drive]); return 0; out3: release_region(HD_DATA, 8); out2: free_irq(HD_IRQ, NULL); out1: for (drive = 0; drive < NR_HD; drive++) put_disk(hd_gendisk[drive]); NR_HD = 0; out: del_timer(&device_timer); unregister_blkdev(HD_MAJOR, "hd"); blk_cleanup_queue(hd_queue); return -1; Enomem: while (drive--) put_disk(hd_gendisk[drive]); goto out; }

Contributors

PersonTokensPropCommitsCommitProp
al viroal viro26159.73%615.79%
pre-gitpre-git11325.86%2155.26%
martin daleckimartin dalecki286.41%12.63%
jens axboejens axboe184.12%12.63%
linus torvaldslinus torvalds71.60%25.26%
christoph hellwigchristoph hellwig40.92%12.63%
martin k. petersenmartin k. petersen20.46%25.26%
lucas de marchilucas de marchi10.23%12.63%
h. peter anvinh. peter anvin10.23%12.63%
andrew mortonandrew morton10.23%12.63%
michael opdenackermichael opdenacker10.23%12.63%
Total437100.00%38100.00%


static int __init parse_hd_setup(char *line) { int ints[6]; (void) get_options(line, ARRAY_SIZE(ints), ints); hd_setup(NULL, ints); return 1; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git4197.62%266.67%
maximilian attemsmaximilian attems12.38%133.33%
Total42100.00%3100.00%

__setup("hd=", parse_hd_setup); late_initcall(hd_init);

Overall Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git241269.35%6053.57%
al viroal viro53015.24%76.25%
martin daleckimartin dalecki2005.75%54.46%
tejun heotejun heo1554.46%65.36%
jens axboejens axboe561.61%54.46%
linus torvaldslinus torvalds320.92%21.79%
andrew mortonandrew morton240.69%32.68%
christoph hellwigchristoph hellwig220.63%32.68%
bartlomiej zolnierkiewiczbartlomiej zolnierkiewicz150.43%32.68%
thomas gleixnerthomas gleixner60.17%21.79%
dave jonesdave jones40.12%10.89%
nicolas kaisernicolas kaiser30.09%10.89%
boaz harroshboaz harrosh30.09%10.89%
arnaldo carvalho de meloarnaldo carvalho de melo30.09%10.89%
martin k. petersenmartin k. petersen20.06%21.79%
adrian bunkadrian bunk20.06%21.79%
ingo molnaringo molnar20.06%10.89%
lucas de marchilucas de marchi10.03%10.89%
ralf baechleralf baechle10.03%10.89%
alexey dobriyanalexey dobriyan10.03%10.89%
maximilian attemsmaximilian attems10.03%10.89%
michael opdenackermichael opdenacker10.03%10.89%
h. peter anvinh. peter anvin10.03%10.89%
andi drebesandi drebes10.03%10.89%
Total3478100.00%112100.00%
Directory: drivers/block
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}