summaryrefslogtreecommitdiffstats
path: root/drivers/block/ll_rw_blk.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/block/ll_rw_blk.c')
-rw-r--r--drivers/block/ll_rw_blk.c201
1 files changed, 142 insertions, 59 deletions
diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
index 05fcf157d..53c1f97a0 100644
--- a/drivers/block/ll_rw_blk.c
+++ b/drivers/block/ll_rw_blk.c
@@ -15,6 +15,7 @@
#include <linux/string.h>
#include <linux/config.h>
#include <linux/locks.h>
+#include <linux/mm.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -40,16 +41,29 @@ int read_ahead[MAX_BLKDEV] = {0, };
* next-request
*/
struct blk_dev_struct blk_dev[MAX_BLKDEV] = {
- { NULL, NULL }, /* no_dev */
- { NULL, NULL }, /* dev mem */
- { NULL, NULL }, /* dev fd */
- { NULL, NULL }, /* dev hd */
- { NULL, NULL }, /* dev ttyx */
- { NULL, NULL }, /* dev tty */
- { NULL, NULL }, /* dev lp */
- { NULL, NULL }, /* dev pipes */
- { NULL, NULL }, /* dev sd */
- { NULL, NULL } /* dev st */
+ { NULL, NULL }, /* 0 no_dev */
+ { NULL, NULL }, /* 1 dev mem */
+ { NULL, NULL }, /* 2 dev fd */
+ { NULL, NULL }, /* 3 dev ide0 or hd */
+ { NULL, NULL }, /* 4 dev ttyx */
+ { NULL, NULL }, /* 5 dev tty */
+ { NULL, NULL }, /* 6 dev lp */
+ { NULL, NULL }, /* 7 dev pipes */
+ { NULL, NULL }, /* 8 dev sd */
+ { NULL, NULL }, /* 9 dev st */
+ { NULL, NULL }, /* 10 */
+ { NULL, NULL }, /* 11 */
+ { NULL, NULL }, /* 12 */
+ { NULL, NULL }, /* 13 */
+ { NULL, NULL }, /* 14 */
+ { NULL, NULL }, /* 15 */
+ { NULL, NULL }, /* 16 */
+ { NULL, NULL }, /* 17 */
+ { NULL, NULL }, /* 18 */
+ { NULL, NULL }, /* 19 */
+ { NULL, NULL }, /* 20 */
+ { NULL, NULL }, /* 21 */
+ { NULL, NULL } /* 22 dev ide1 */
};
/*
@@ -72,6 +86,57 @@ int * blk_size[MAX_BLKDEV] = { NULL, NULL, };
int * blksize_size[MAX_BLKDEV] = { NULL, NULL, };
/*
+ * hardsect_size contains the size of the hardware sector of a device.
+ *
+ * hardsect_size[MAJOR][MINOR]
+ *
+ * if (!hardsect_size[MAJOR])
+ * then 512 bytes is assumed.
+ * else
+ * sector_size is hardsect_size[MAJOR][MINOR]
+ * This is currently set by some scsi device and read by the msdos fs driver
+ * This might be a some uses later.
+ */
+int * hardsect_size[MAX_BLKDEV] = { NULL, NULL, };
+
+/*
+ * "plug" the device if there are no outstanding requests: this will
+ * force the transfer to start only after we have put all the requests
+ * on the list.
+ */
+static void plug_device(struct blk_dev_struct * dev, struct request * plug)
+{
+ unsigned long flags;
+
+ plug->dev = -1;
+ plug->cmd = -1;
+ plug->next = NULL;
+ save_flags(flags);
+ cli();
+ if (!dev->current_request)
+ dev->current_request = plug;
+ restore_flags(flags);
+}
+
+/*
+ * remove the plug and let it rip..
+ */
+static void unplug_device(struct blk_dev_struct * dev)
+{
+ struct request * req;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ req = dev->current_request;
+ if (req && req->dev == -1 && req->cmd == -1) {
+ dev->current_request = req->next;
+ (dev->request_fn)();
+ }
+ restore_flags(flags);
+}
+
+/*
* look for a free request in the first N entries.
* NOTE: interrupts must be disabled on the way in, and will still
* be disabled on the way out.
@@ -104,18 +169,40 @@ static inline struct request * get_request(int n, int dev)
/*
* wait until a free request in the first N entries is available.
- * NOTE: interrupts must be disabled on the way in, and will still
- * be disabled on the way out.
*/
-static inline struct request * get_request_wait(int n, int dev)
+static struct request * __get_request_wait(int n, int dev)
{
register struct request *req;
+ struct wait_queue wait = { current, NULL };
- while ((req = get_request(n, dev)) == NULL)
- sleep_on(&wait_for_request);
+ add_wait_queue(&wait_for_request, &wait);
+ for (;;) {
+ unplug_device(MAJOR(dev)+blk_dev);
+ current->state = TASK_UNINTERRUPTIBLE;
+ cli();
+ req = get_request(n, dev);
+ sti();
+ if (req)
+ break;
+ schedule();
+ }
+ remove_wait_queue(&wait_for_request, &wait);
+ current->state = TASK_RUNNING;
return req;
}
+static inline struct request * get_request_wait(int n, int dev)
+{
+ register struct request *req;
+
+ cli();
+ req = get_request(n, dev);
+ sti();
+ if (req)
+ return req;
+ return __get_request_wait(n, dev);
+}
+
/* RO fail safe mechanism */
static long ro_bits[MAX_BLKDEV][8];
@@ -157,10 +244,11 @@ static void add_request(struct blk_dev_struct * dev, struct request * req)
kstat.dk_drive[disk_index]++;
break;
case HD_MAJOR:
- case XT_DISK_MAJOR: disk_index = (MINOR(req->dev) & 0x00C0) >> 6;
- if (disk_index < 4)
- kstat.dk_drive[disk_index]++;
+ case XT_DISK_MAJOR: disk_index = (MINOR(req->dev) & 0x0040) >> 6;
+ kstat.dk_drive[disk_index]++;
break;
+ case IDE1_MAJOR: disk_index = ((MINOR(req->dev) & 0x0040) >> 6) + 2;
+ kstat.dk_drive[disk_index]++;
default: break;
}
@@ -219,6 +307,10 @@ static void make_request(int major,int rw, struct buffer_head * bh)
bh->b_req = 0;
return;
}
+ /* Uhhuh.. Nasty dead-lock possible here.. */
+ if (bh->b_lock)
+ return;
+ /* Maybe the above fixes it, and maybe it doesn't boot. Life is interesting */
lock_buffer(bh);
if ((rw == WRITE && !bh->b_dirt) || (rw == READ && bh->b_uptodate)) {
unlock_buffer(bh);
@@ -231,22 +323,25 @@ static void make_request(int major,int rw, struct buffer_head * bh)
*/
max_req = (rw == READ) ? NR_REQUEST : ((NR_REQUEST*2)/3);
-/* big loop: look for a free request. */
-
-repeat:
+/* look for a free request. */
cli();
-/* The scsi disk drivers completely remove the request from the queue when
- * they start processing an entry. For this reason it is safe to continue
- * to add links to the top entry for scsi devices.
+/* The scsi disk drivers and the IDE driver completely remove the request
+ * from the queue when they start processing an entry. For this reason
+ * it is safe to continue to add links to the top entry for those devices.
*/
- if ((major == HD_MAJOR
+ if (( major == IDE0_MAJOR /* same as HD_MAJOR */
+ || major == IDE1_MAJOR
|| major == FLOPPY_MAJOR
|| major == SCSI_DISK_MAJOR
|| major == SCSI_CDROM_MAJOR)
&& (req = blk_dev[major].current_request))
{
+#ifdef CONFIG_BLK_DEV_HD
if (major == HD_MAJOR || major == FLOPPY_MAJOR)
+#else
+ if (major == FLOPPY_MAJOR)
+#endif CONFIG_BLK_DEV_HD
req = req->next;
while (req) {
if (req->dev == bh->b_dev &&
@@ -286,22 +381,17 @@ repeat:
/* find an unused request. */
req = get_request(max_req, bh->b_dev);
+ sti();
-/* if no request available: if rw_ahead, forget it; otherwise try again. */
- if (! req) {
+/* if no request available: if rw_ahead, forget it; otherwise try again blocking.. */
+ if (!req) {
if (rw_ahead) {
- sti();
unlock_buffer(bh);
return;
}
- sleep_on(&wait_for_request);
- sti();
- goto repeat;
+ req = __get_request_wait(max_req, bh->b_dev);
}
-/* we found a request. */
- sti();
-
/* fill up the request-info, and add it to the queue */
req->cmd = rw;
req->errors = 0;
@@ -316,14 +406,15 @@ repeat:
add_request(major+blk_dev,req);
}
-void ll_rw_page(int rw, int dev, int page, char * buffer)
+void ll_rw_page(int rw, int dev, unsigned long page, char * buffer)
{
struct request * req;
unsigned int major = MAJOR(dev);
+ unsigned long sector = page * (PAGE_SIZE / 512);
struct semaphore sem = MUTEX_LOCKED;
if (major >= MAX_BLKDEV || !(blk_dev[major].request_fn)) {
- printk("Trying to read nonexistent block-device %04x (%d)\n",dev,page*8);
+ printk("Trying to read nonexistent block-device %04x (%ld)\n",dev,sector);
return;
}
if (rw!=READ && rw!=WRITE)
@@ -332,15 +423,13 @@ void ll_rw_page(int rw, int dev, int page, char * buffer)
printk("Can't page to read-only device 0x%X\n",dev);
return;
}
- cli();
req = get_request_wait(NR_REQUEST, dev);
- sti();
/* fill up the request-info, and add it to the queue */
req->cmd = rw;
req->errors = 0;
- req->sector = page<<3;
- req->nr_sectors = 8;
- req->current_nr_sectors = 8;
+ req->sector = sector;
+ req->nr_sectors = PAGE_SIZE / 512;
+ req->current_nr_sectors = PAGE_SIZE / 512;
req->buffer = buffer;
req->sem = &sem;
req->bh = NULL;
@@ -357,7 +446,6 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bh[])
{
unsigned int major;
struct request plug;
- int plugged;
int correct_size;
struct blk_dev_struct * dev;
int i;
@@ -407,15 +495,8 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bh[])
from starting until we have shoved all of the blocks into the
queue, and then we let it rip. */
- plugged = 0;
- cli();
- if (!dev->current_request && nr > 1) {
- dev->current_request = &plug;
- plug.dev = -1;
- plug.next = NULL;
- plugged = 1;
- }
- sti();
+ if (nr > 1)
+ plug_device(dev, &plug);
for (i = 0; i < nr; i++) {
if (bh[i]) {
bh[i]->b_req = 1;
@@ -426,12 +507,7 @@ void ll_rw_block(int rw, int nr, struct buffer_head * bh[])
kstat.pgpgout++;
}
}
- if (plugged) {
- cli();
- dev->current_request = plug.next;
- (dev->request_fn)();
- sti();
- }
+ unplug_device(dev);
return;
sorry:
@@ -468,9 +544,7 @@ void ll_rw_swap_file(int rw, int dev, unsigned int *b, int nb, char *buf)
for (i=0; i<nb; i++, buf += buffersize)
{
- cli();
req = get_request_wait(NR_REQUEST, dev);
- sti();
req->cmd = rw;
req->errors = 0;
req->sector = (b[i] * buffersize) >> 9;
@@ -498,15 +572,24 @@ long blk_dev_init(long mem_start, long mem_end)
#ifdef CONFIG_BLK_DEV_HD
mem_start = hd_init(mem_start,mem_end);
#endif
+#ifdef CONFIG_BLK_DEV_IDE
+ mem_start = ide_init(mem_start,mem_end);
+#endif
#ifdef CONFIG_BLK_DEV_XD
mem_start = xd_init(mem_start,mem_end);
#endif
#ifdef CONFIG_CDU31A
mem_start = cdu31a_init(mem_start,mem_end);
#endif
+#ifdef CONFIG_CDU535
+ mem_start = sony535_init(mem_start,mem_end);
+#endif
#ifdef CONFIG_MCD
mem_start = mcd_init(mem_start,mem_end);
#endif
+#ifdef CONFIG_AZTCD
+ mem_start = aztcd_init(mem_start,mem_end);
+#endif
#ifdef CONFIG_BLK_DEV_FD
floppy_init();
#else