OpenCores
URL https://opencores.org/ocsvn/or1k_old/or1k_old/trunk

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [rc203soc/] [sw/] [uClinux/] [arch/] [armnommu/] [drivers/] [block/] [mfmhd.c] - Blame information for rev 1782

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1622 jcastillo
/*
2
 * linux/arch/arm/drivers/block/mfmhd.c
3
 *
4
 * Copyright (C) 1995, 1996 Russell King, Dave Alan Gilbert (linux@treblig.org)
5
 *
6
 * MFM hard drive code [experimental]
7
 */
8
 
9
/*
10
 * Change list:
11
 *
12
 *  3/2/96:DAG: Started a change list :-)
13
 *              Set the hardsect_size pointers up since we are running 256 byte
14
 *                sectors
15
 *              Added DMA code, put it into the rw_intr
16
 *              Moved RCAL out of generic interrupt code - don't want to do it
17
 *                while DMA'ing - its now in individual handlers.
18
 *              Took interrupt handlers off task queue lists and called
19
 *                directly - not sure of implications.
20
 *
21
 * 18/2/96:DAG: Well its reading OK I think, well enough for image file code
22
 *              to find the image file; but now I've discovered that I actually
23
 *              have to put some code in for image files.
24
 *
25
 *              Added stuff for image files; seems to work, but I've not
26
 *              got a multisegment image file (I don't think!).
27
 *              Put in a hack (yep a real hack) for multiple cylinder reads.
28
 *              Not convinced its working.
29
 *
30
 *  5/4/96:DAG: Added asm/hardware.h and use IOC_ macros
31
 *              Rewrote dma code in mfm.S (again!) - now takes a word at a time
32
 *              from main RAM for speed; still doesn't feel speedy!
33
 *
34
 * 20/4/96:DAG: After rewriting mfm.S a heck of a lot of times and speeding
35
 *              things up, I've finally figured out why its so damn slow.
36
 *              Linux is only reading a block at a time, and so you never
37
 *              get more than 1K per disc revoloution ~=60K/second.
38
 *
39
 * 27/4/96:DAG: On Russell's advice I change ll_rw_blk.c to ask it to
40
 *              join adjacent blocks together. Everything falls flat on its
41
 *              face.
42
 *              Four hours of debugging later; I hadn't realised that
43
 *              ll_rw_blk would be so generous as to join blocks whose
44
 *              results aren't going into consecutive buffers.
45
 *
46
 *              OK; severe rehacking of mfm_rw_interrupt; now end_request's
47
 *              as soon as its DMA'd each request.  Odd thing is that
48
 *              we are sometimes getting interrupts where we are not transferring
49
 *              any data; why? Is that what happens when you miss? I doubt
50
 *              it; are we too fast? No - its just at command ends. Got 240K/s
51
 *              better than before, but RiscOS hits 480K/s
52
 *
53
 * 25/6/96:RMK: Fixed init code to allow the MFM podule to work.  Increased the
54
 *              number of errors for my Miniscribe drive (8425).
55
 *
56
 * 30/6/96:DAG: Russell suggested that a check drive 0 might turn the LEDs off
57
 *              - so in request_done just before it clears Busy it sends a
58
 *              check drive 0 - and the LEDs go off!!!!
59
 *
60
 *              Added test for mainboard controller. - Removes need for separate
61
 *              define.
62
 *
63
 * 13/7/96:DAG: Changed hardware sectore size to 512 in attempt to make
64
 *              IM drivers work.
65
 * 21/7/96:DAG: Took out old image file stuff (accessing it now produces an IO
66
 *              error.)
67
 *
68
 * 17/8/96:DAG: Ran through indent -kr -i8; evil - all my nice 2 character indents
69
 *              gone :-( Hand modified afterwards.
70
 *              Took out last remains of the older image map system.
71
 *
72
 * 22/9/96:DAG: Changed mfm.S so it will carry on DMA'ing til; BSY is dropped
73
 *              Changed mfm_rw_intr so that it doesn't follow the error
74
 *              code until BSY is dropped. Nope - still broke. Problem
75
 *              may revolve around when it reads the results for the error
76
 *              number?
77
 *
78
 *16/11/96:DAG: Modified for 2.0.18; request_irq changed
79
 *
80
 *17/12/96:RMK: Various cleanups, reorganisation, and the changes for new IO system.
81
 *              Improved probe for onboard MFM chip - it was hanging on my A5k.
82
 *              Added autodetect CHS code such that we don't rely on the presence
83
 *              of an ADFS boot block.  Added ioport resource manager calls so
84
 *              that we don't clash with already-running hardware (eg. RiscPC Ether
85
 *              card slots if someone tries this)!
86
 */
87
 
88
/*
89
 * Possible enhancements:
90
 *  Multi-thread the code so that it is possible that while one drive
91
 *  is seeking, the other one can be reading data/seeking as well.
92
 *  This would be a performance boost with dual drive systems.
93
 */
94
 
95
#include <linux/module.h>
96
#include <linux/config.h>
97
#include <linux/sched.h>
98
#include <linux/fs.h>
99
#include <linux/interrupt.h>
100
#include <linux/kernel.h>
101
#include <linux/timer.h>
102
#include <linux/tqueue.h>
103
#include <linux/mm.h>
104
#include <linux/errno.h>
105
#include <linux/genhd.h>
106
#include <linux/major.h>
107
#include <linux/ioport.h>
108
 
109
#include <asm/system.h>
110
#include <asm/io.h>
111
#include <asm/irq.h>
112
#include <asm/segment.h>
113
#include <asm/delay.h>
114
#include <asm/dma.h>
115
#include <asm/hardware.h>
116
#include <asm/ecard.h>
117
 
118
#define MFM_DISK_MAJOR  13
119
#undef  XT_DISK_MAJOR
120
#define XT_DISK_MAJOR   -1
121
#define MAJOR_NR        MFM_DISK_MAJOR
122
#include "blk.h"
123
 
124
/*
125
 * This sort of stuff should be in a header file shared with ide.c, hd.c, xd.c etc
126
 */
127
#ifndef HDIO_GETGEO
128
#define HDIO_GETGEO 0x301
129
struct hd_geometry {
130
        unsigned char heads;
131
        unsigned char sectors;
132
        unsigned short cylinders;
133
        unsigned long start;
134
};
135
#endif
136
 
137
 
138
/*
139
 * Configuration section
140
 *
141
 * Enable MFM_AUTODETECT_DRIVES to allow the code to find out the real CHS
142
 * for the drive.
143
 */
144
#define MFM_AUTODETECT_DRIVES
145
/*
146
 * This is the maximum number of drives that we accept
147
 */
148
#define MFM_MAXDRIVES 2
149
/*
150
 * Linux I/O address of onboard MFM controller or 0 to disable this
151
 */
152
#define ONBOARD_MFM_ADDRESS ((0x002d0000 >> 2) | 0x80000000)
153
/*
154
 * Uncomment this to enable debugging in the MFM driver...
155
 */
156
#ifndef DEBUG
157
/*#define DEBUG */
158
#endif
159
/*
160
 * List of card types that we recognise
161
 */
162
static const card_ids mfm_cids[] = {
163
        { MANU_ACORN, PROD_ACORN_MFM },
164
        { 0xffff, 0xffff }
165
};
166
/*
167
 * End of configuration
168
 */
169
 
170
 
171
/*
172
 * This structure contains all information to do with a particular physical
173
 * device.
174
 */
175
struct mfm_info {
176
        unsigned char sectors;
177
        unsigned char heads;
178
        unsigned short cylinders;
179
        unsigned short lowcurrent;
180
        unsigned short precomp;
181
#define NO_TRACK -1
182
#define NEED_1_RECAL -2
183
#define NEED_2_RECAL -3
184
                 int cylinder;
185
        unsigned int access_count;
186
        unsigned int busy;
187
        struct {
188
                char recal;
189
                char report;
190
                char abort;
191
        } errors;
192
} mfm_info[MFM_MAXDRIVES];
193
 
194
#define MFM_DRV_INFO mfm_info[raw_cmd.dev]
195
 
196
static struct hd_struct mfm[MFM_MAXDRIVES << 6];
197
static int mfm_sizes[MFM_MAXDRIVES << 6];
198
static int mfm_blocksizes[MFM_MAXDRIVES << 6];
199
static int mfm_sectsizes[MFM_MAXDRIVES << 6];
200
static struct wait_queue *mfm_wait_open = NULL;
201
 
202
/* Stuff from the assembly routines */
203
extern unsigned int hdc63463_baseaddress;       /* Controller base address */
204
extern unsigned int hdc63463_irqpolladdress;    /* Address to read to test for int */
205
extern unsigned int hdc63463_irqpollmask;       /* Mask for irq register */
206
extern unsigned int hdc63463_dataptr;   /* Pointer to kernel data space to DMA */
207
extern int hdc63463_dataleft;   /* Number of bytes left to transfer */
208
 
209
 
210
 
211
 
212
static int lastspecifieddrive;
213
static unsigned Busy;
214
 
215
static unsigned int PartFragRead;       /* The number of sectors which have been read
216
                                           during a partial read split over two
217
                                           cylinders.  If 0 it means a partial
218
                                           read did not occur. */
219
 
220
static unsigned int PartFragRead_RestartBlock;  /* Where to restart on a split access */
221
static unsigned int PartFragRead_SectorsLeft;   /* Where to restart on a split access */
222
 
223
static int Sectors256LeftInCurrent;     /* i.e. 256 byte sectors left in current */
224
static int SectorsLeftInRequest;        /* i.e. blocks left in the thing mfm_request was called for */
225
static int Copy_Sector;         /* The 256 byte sector we are currently at - fragments need to know
226
                                   where to take over */
227
static char *Copy_buffer;
228
 
229
 
230
static void mfm_seek(void);
231
static void mfm_rerequest(void);
232
static void mfm_request(void);
233
static int mfm_reread_partitions(kdev_t dev);
234
static void mfm_specify (void);
235
static void issue_request(int dev, unsigned int block, unsigned int nsect,
236
                          struct request *req);
237
 
238
#define mfm_init xd_init
239
#define mfm_setup xd_setup
240
 
241
static unsigned int mfm_addr;           /* Controller address */
242
static unsigned int mfm_IRQPollLoc;     /* Address to read for IRQ information */
243
static unsigned int mfm_irqenable;      /* Podule IRQ enable location */
244
static unsigned char mfm_irq;           /* Interrupt number */
245
static int mfm_drives = 0;               /* drives available */
246
static int mfm_status = 0;               /* interrupt status */
247
static int *errors;
248
 
249
static struct rawcmd {
250
        unsigned int dev;
251
        unsigned int cylinder;
252
        unsigned int head;
253
        unsigned int sector;
254
        unsigned int cmdtype;
255
        unsigned int cmdcode;
256
        unsigned char cmddata[16];
257
        unsigned int cmdlen;
258
} raw_cmd;
259
 
260
static unsigned char result[16];
261
 
262
static struct cont {
263
        void (*interrupt) (void);       /* interrupt handler */
264
        void (*error) (void);   /* error handler */
265
        void (*redo) (void);    /* redo handler */
266
        void (*done) (int st);  /* done handler */
267
} *cont = NULL;
268
 
269
static struct tq_struct mfm_tq = {0, 0, (void (*)(void *)) NULL, 0};
270
 
271
int number_mfm_drives = 1;
272
 
273
/* ------------------------------------------------------------------------------------------ */
274
/*
275
 * From the HD63463 data sheet from Hitachi Ltd.
276
 */
277
 
278
#define MFM_COMMAND (mfm_addr + 0)
279
#define MFM_DATAOUT (mfm_addr + 1)
280
#define MFM_STATUS  (mfm_addr + 8)
281
#define MFM_DATAIN  (mfm_addr + 9)
282
 
283
#define CMD_ABT         0xF0    /* Abort */
284
#define CMD_SPC         0xE8    /* Specify */
285
#define CMD_TST         0xE0    /* Test */
286
#define CMD_RCLB        0xC8    /* Recalibrate */
287
#define CMD_SEK         0xC0    /* Seek */
288
#define CMD_WFS         0xAB    /* Write Format Skew */
289
#define CMD_WFM         0xA3    /* Write Format */
290
#define CMD_MTB         0x90    /* Memory to buffer */
291
#define CMD_CMPD        0x88    /* Compare data */
292
#define CMD_WD          0x87    /* Write data */
293
#define CMD_RED         0x70    /* Read erroneous data */
294
#define CMD_RIS         0x68    /* Read ID skew */
295
#define CMD_FID         0x61    /* Find ID */
296
#define CMD_RID         0x60    /* Read ID */
297
#define CMD_BTM         0x50    /* Buffer to memory */
298
#define CMD_CKD         0x48    /* Check data */
299
#define CMD_RD          0x40    /* Read data */
300
#define CMD_OPBW        0x38    /* Open buffer write */
301
#define CMD_OPBR        0x30    /* Open buffer read */
302
#define CMD_CKV         0x28    /* Check drive */
303
#define CMD_CKE         0x20    /* Check ECC */
304
#define CMD_POD         0x18    /* Polling disable */
305
#define CMD_POL         0x10    /* Polling enable */
306
#define CMD_RCAL        0x08    /* Recall */
307
 
308
#define STAT_BSY        0x8000  /* Busy */
309
#define STAT_CPR        0x4000  /* Command Parameter Rejection */
310
#define STAT_CED        0x2000  /* Command end */
311
#define STAT_SED        0x1000  /* Seek end */
312
#define STAT_DER        0x0800  /* Drive error */
313
#define STAT_ABN        0x0400  /* Abnormal end */
314
#define STAT_POL        0x0200  /* Polling */
315
 
316
/* ------------------------------------------------------------------------------------------ */
317
#ifdef DEBUG
318
static void console_printf(const char *fmt,...)
319
{
320
        static char buffer[2048];       /* Arbitary! */
321
        extern void console_print(const char *);
322
        unsigned long flags;
323
        va_list ap;
324
 
325
        save_flags_cli(flags);
326
 
327
        va_start(ap, fmt);
328
        vsprintf(buffer, fmt, ap);
329
        console_print(buffer);
330
        va_end(fmt);
331
 
332
        restore_flags(flags);
333
};      /* console_printf */
334
 
335
#define DBG(x...) console_printf(x)
336
#else
337
#define DBG(x...)
338
#endif
339
 
340
static void print_status(void)
341
{
342
        char *error;
343
        static char *errors[] = {
344
         "no error",
345
         "command aborted",
346
         "invalid command",
347
         "parameter error",
348
         "not initialised",
349
         "rejected TEST",
350
         "no useld",
351
         "write fault",
352
         "not ready",
353
         "no scp",
354
         "in seek",
355
         "invalid NCA",
356
         "invalid step rate",
357
         "seek error",
358
         "over run",
359
         "invalid PHA",
360
         "data field EEC error",
361
         "data field CRC error",
362
         "error corrected",
363
         "data field fatal error",
364
         "no data am",
365
         "not hit",
366
         "ID field CRC error",
367
         "time over",
368
         "no ID am",
369
         "not writable"
370
        };
371
        if (result[1] < 0x65)
372
                error = errors[result[1] >> 2];
373
        else
374
                error = "unknown";
375
        printk("(");
376
        if (mfm_status & STAT_BSY) printk("BSY ");
377
        if (mfm_status & STAT_CPR) printk("CPR ");
378
        if (mfm_status & STAT_CED) printk("CED ");
379
        if (mfm_status & STAT_SED) printk("SED ");
380
        if (mfm_status & STAT_DER) printk("DER ");
381
        if (mfm_status & STAT_ABN) printk("ABN ");
382
        if (mfm_status & STAT_POL) printk("POL ");
383
        printk(") SSB = %X (%s)\n", result[1], error);
384
 
385
}
386
 
387
/* ------------------------------------------------------------------------------------- */
388
 
389
static void issue_command(int command, unsigned char *cmdb, int len)
390
{
391
        int status;
392
#ifdef DEBUG
393
        int i;
394
        console_printf("issue_command: %02X: ", command);
395
        for (i = 0; i < len; i++)
396
                console_printf("%02X ", cmdb[i]);
397
        console_printf("\n");
398
#endif
399
 
400
        do {
401
                status = inw(MFM_STATUS);
402
        } while (status & (STAT_BSY | STAT_POL));
403
        DBG("issue_command: status after pol/bsy loop: %02X:\n ", status >> 8);
404
 
405
        if (status & (STAT_CPR | STAT_CED | STAT_SED | STAT_DER | STAT_ABN)) {
406
                outw(CMD_RCAL, MFM_COMMAND);
407
                while (inw(MFM_STATUS) & STAT_BSY);
408
        }
409
        status = inw(MFM_STATUS);
410
        DBG("issue_command: status before parameter issue: %02X:\n ", status >> 8);
411
 
412
        while (len > 0) {
413
                outw(cmdb[1] | (cmdb[0] << 8), MFM_DATAOUT);
414
                len -= 2;
415
                cmdb += 2;
416
        }
417
        status = inw(MFM_STATUS);
418
        DBG("issue_command: status before command issue: %02X:\n ", status >> 8);
419
 
420
        outw(command, MFM_COMMAND);
421
        status = inw(MFM_STATUS);
422
        DBG("issue_command: status immediatly after command issue: %02X:\n ", status >> 8);
423
}
424
 
425
static void wait_for_completion(void)
426
{
427
        while ((mfm_status = inw(MFM_STATUS)) & STAT_BSY);
428
}
429
 
430
static void wait_for_command_end(void)
431
{
432
        int i;
433
 
434
        while (!((mfm_status = inw(MFM_STATUS)) & STAT_CED));
435
 
436
        for (i = 0; i < 16;) {
437
                int in;
438
                in = inw(MFM_DATAIN);
439
                result[i++] = in >> 8;
440
                result[i++] = in;
441
        }
442
        outw (CMD_RCAL, MFM_COMMAND);
443
}
444
 
445
/* ------------------------------------------------------------------------------------- */
446
 
447
static void mfm_rw_intr(void)
448
{
449
        int old_status;         /* Holds status on entry, we read to see if the command just finished */
450
#ifdef DEBUG
451
        console_printf("mfm_rw_intr...dataleft=%d\n", hdc63463_dataleft);
452
        print_status();
453
#endif
454
 
455
  /* Now don't handle the error until BSY drops */
456
        if ((mfm_status & (STAT_DER | STAT_ABN)) && ((mfm_status&STAT_BSY)==0)) {
457
                /* Something has gone wrong - lets try that again */
458
                outw(CMD_RCAL, MFM_COMMAND);    /* Clear interrupt condition */
459
                if (cont) {
460
                        DBG("mfm_rw_intr: DER/ABN err\n");
461
                        cont->error();
462
                        cont->redo();
463
                };
464
                return;
465
        };
466
 
467
        /* OK so what ever happend its not an error, now I reckon we are left between
468
           a choice of command end or some data which is ready to be collected */
469
        /* I think we have to transfer data while the interrupt line is on and its
470
           not any other type of interrupt */
471
        if (CURRENT->cmd == WRITE) {
472
                extern void hdc63463_writedma(void);
473
                if ((hdc63463_dataleft <= 0) && (!(mfm_status & STAT_CED))) {
474
                        printk("mfm_rw_intr: Apparent DMA write request when no more to DMA\n");
475
                        if (cont) {
476
                                cont->error();
477
                                cont->redo();
478
                        };
479
                        return;
480
                };
481
                hdc63463_writedma();
482
        } else {
483
                extern void hdc63463_readdma(void);
484
                if ((hdc63463_dataleft <= 0) && (!(mfm_status & STAT_CED))) {
485
                        printk("mfm_rw_intr: Apparent DMA read request when no more to DMA\n");
486
                        if (cont) {
487
                                cont->error();
488
                                cont->redo();
489
                        };
490
                        return;
491
                };
492
                DBG("Going to try read dma..............status=0x%x, buffer=%p\n", mfm_status, hdc63463_dataptr);
493
                hdc63463_readdma();
494
        };                      /* Read */
495
 
496
        if (hdc63463_dataptr != ((unsigned int) Copy_buffer + 256)) {
497
                /* If we didn't actually manage to get any data on this interrupt - but why? We got the interrupt */
498
                /* Ah - well looking at the status its just when we get command end; so no problem */
499
                /*console_printf("mfm: dataptr mismatch. dataptr=0x%08x Copy_buffer+256=0x%08p\n",
500
                   hdc63463_dataptr,Copy_buffer+256);
501
                   print_status(); */
502
        } else {
503
                Sectors256LeftInCurrent--;
504
                Copy_buffer += 256;
505
                Copy_Sector++;
506
 
507
                /* We have come to the end of this request */
508
                if (!Sectors256LeftInCurrent) {
509
                        DBG("mfm: end_request for CURRENT=0x%p CURRENT(sector=%d current_nr_sectors=%d nr_sectors=%d)\n",
510
                                       CURRENT, CURRENT->sector, CURRENT->current_nr_sectors, CURRENT->nr_sectors);
511
 
512
                        CURRENT->nr_sectors -= CURRENT->current_nr_sectors;
513
                        CURRENT->sector += CURRENT->current_nr_sectors;
514
                        SectorsLeftInRequest -= CURRENT->current_nr_sectors;
515
 
516
                        end_request(1);
517
                        if (SectorsLeftInRequest) {
518
                                hdc63463_dataptr = (unsigned int) CURRENT->buffer;
519
                                Copy_buffer = CURRENT->buffer;
520
                                Sectors256LeftInCurrent = CURRENT->current_nr_sectors * 2;
521
                                errors = &(CURRENT->errors);
522
                                /* These should match the present calculations of the next logical sector
523
                                   on the device
524
                                   Copy_Sector=CURRENT->sector*2; */
525
 
526
                                if (Copy_Sector != CURRENT->sector * 2)
527
#ifdef DEBUG
528
                                        /*console_printf*/printk("mfm: Copy_Sector mismatch. Copy_Sector=%d CURRENT->sector*2=%d\n",
529
                                        Copy_Sector, CURRENT->sector * 2);
530
#else
531
                                        printk("mfm: Copy_Sector mismatch! Eek!\n");
532
#endif
533
                        };      /* CURRENT */
534
                };      /* Sectors256LeftInCurrent */
535
        };
536
 
537
        old_status = mfm_status;
538
        mfm_status = inw(MFM_STATUS);
539
        if (mfm_status & (STAT_DER | STAT_ABN)) {
540
                /* Something has gone wrong - lets try that again */
541
                if (cont) {
542
                        DBG("mfm_rw_intr: DER/ABN error\n");
543
                        cont->error();
544
                        cont->redo();
545
                };
546
                return;
547
        };
548
 
549
        /* If this code wasn't entered due to command_end but there is
550
           now a command end we must read the command results out. If it was
551
           entered like this then mfm_interrupt_handler would have done the
552
           job. */
553
        if ((!((old_status & (STAT_CPR | STAT_BSY)) == STAT_CPR)) &&
554
            ((mfm_status & (STAT_CPR | STAT_BSY)) == STAT_CPR)) {
555
                int len = 0;
556
                while (len < 16) {
557
                        int in;
558
                        in = inw(MFM_DATAIN);
559
                        result[len++] = in >> 8;
560
                        result[len++] = in;
561
                };
562
        };                      /* Result read */
563
 
564
        /*console_printf ("mfm_rw_intr nearexit [%02X]\n", inb(mfm_IRQPollLoc)); */
565
 
566
        /* If end of command move on */
567
        if (mfm_status & (STAT_CED)) {
568
                outw(CMD_RCAL, MFM_COMMAND);    /* Clear interrupt condition */
569
                /* End of command - trigger the next command */
570
                if (cont) {
571
                        cont->done(1);
572
                }
573
                DBG("mfm_rw_intr: returned from cont->done\n");
574
        } else {
575
                /* Its going to generate another interrupt */
576
                SET_INTR(mfm_rw_intr);
577
        };
578
}
579
 
580
static void mfm_setup_rw(void)
581
{
582
        DBG("setting up for rw...\n");
583
 
584
        SET_INTR(mfm_rw_intr);
585
        issue_command(raw_cmd.cmdcode, raw_cmd.cmddata, raw_cmd.cmdlen);
586
}
587
 
588
static void mfm_recal_intr(void)
589
{
590
#ifdef DEBUG
591
        console_printf("recal intr - status = ");
592
        print_status();
593
#endif
594
        outw(CMD_RCAL, MFM_COMMAND);    /* Clear interrupt condition */
595
        if (mfm_status & (STAT_DER | STAT_ABN)) {
596
                printk("recal failed\n");
597
                MFM_DRV_INFO.cylinder = NEED_2_RECAL;
598
                if (cont) {
599
                        cont->error();
600
                        cont->redo();
601
                }
602
                return;
603
        }
604
        /* Thats seek end - we are finished */
605
        if (mfm_status & STAT_SED) {
606
                issue_command(CMD_POD, NULL, 0);
607
                MFM_DRV_INFO.cylinder = 0;
608
                mfm_seek();
609
                return;
610
        }
611
        /* Command end without seek end (see data sheet p.20) for parallel seek
612
           - we have to send a POL command to wait for the seek */
613
        if (mfm_status & STAT_CED) {
614
                SET_INTR(mfm_recal_intr);
615
                issue_command(CMD_POL, NULL, 0);
616
                return;
617
        }
618
        printk("recal: unknown status\n");
619
}
620
 
621
static void mfm_seek_intr(void)
622
{
623
#ifdef DEBUG
624
        console_printf("seek intr - status = ");
625
        print_status();
626
#endif
627
        outw(CMD_RCAL, MFM_COMMAND);    /* Clear interrupt condition */
628
        if (mfm_status & (STAT_DER | STAT_ABN)) {
629
                printk("seek failed\n");
630
                MFM_DRV_INFO.cylinder = NEED_2_RECAL;
631
                if (cont) {
632
                        cont->error();
633
                        cont->redo();
634
                }
635
                return;
636
        }
637
        if (mfm_status & STAT_SED) {
638
                issue_command(CMD_POD, NULL, 0);
639
                MFM_DRV_INFO.cylinder = raw_cmd.cylinder;
640
                mfm_seek();
641
                return;
642
        }
643
        if (mfm_status & STAT_CED) {
644
                SET_INTR(mfm_seek_intr);
645
                issue_command(CMD_POL, NULL, 0);
646
                return;
647
        }
648
        printk("seek: unknown status\n");
649
}
650
 
651
/* IDEA2 seems to work better - its what RiscOS sets my
652
 * disc to - on its SECOND call to specify!
653
 */
654
#define IDEA2
655
#ifndef IDEA2
656
#define SPEC_SL 0x16
657
#define SPEC_SH 0xa9            /* Step pulse high=21, Record Length=001 (256 bytes) */
658
#else
659
#define SPEC_SL 0x00            /* OM2 - SL - step pulse low */
660
#define SPEC_SH 0x21            /* Step pulse high=4, Record Length=001 (256 bytes) */
661
#endif
662
 
663
static void mfm_setupspecify (int drive, unsigned char *cmdb)
664
{
665
        cmdb[0]  = 0x1f;         /* OM0 - !SECT,!MOD,!DIF,PADP,ECD,CRCP,CRCI,ACOR */
666
        cmdb[1]  = 0xc3;                /* OM1 - DTM,BRST,!CEDM,!SEDM,!DERM,0,AMEX,PSK */
667
        cmdb[2]  = SPEC_SL;             /* OM2 - SL - step pulse low */
668
        cmdb[3]  = (number_mfm_drives == 1) ? 0x02 : 0x06;      /* 1 or 2 drives */
669
        cmdb[4]  = 0xfc | ((mfm_info[drive].cylinders - 1) >> 8);/* RW time over/high part of number of cylinders */
670
        cmdb[5]  = mfm_info[drive].cylinders - 1;               /* low part of number of cylinders */
671
        cmdb[6]  = mfm_info[drive].heads - 1;                   /* Number of heads */
672
        cmdb[7]  = mfm_info[drive].sectors - 1;                 /* Number of sectors */
673
        cmdb[8]  = SPEC_SH;
674
        cmdb[9]  = 0x0a;                /* gap length 1 */
675
        cmdb[10] = 0x0d;                /* gap length 2 */
676
        cmdb[11] = 0x0c;                /* gap length 3 */
677
        cmdb[12] = (mfm_info[drive].precomp - 1) >> 8;  /* pre comp cylinder */
678
        cmdb[13] = mfm_info[drive].precomp - 1;
679
        cmdb[14] = (mfm_info[drive].lowcurrent - 1) >> 8;       /* Low current cylinder */
680
        cmdb[15] = mfm_info[drive].lowcurrent - 1;
681
}
682
 
683
static void mfm_specify (void)
684
{
685
        unsigned char cmdb[16];
686
 
687
        DBG("specify...dev=%d lastspecified=%d\n", raw_cmd.dev, lastspecifieddrive);
688
        mfm_setupspecify (raw_cmd.dev, cmdb);
689
 
690
        issue_command (CMD_SPC, cmdb, 16);
691
        /* Ensure that we will do another specify if we move to the other drive */
692
        lastspecifieddrive = raw_cmd.dev;
693
        wait_for_completion();
694
}
695
 
696
static void mfm_seek(void)
697
{
698
        unsigned char cmdb[4];
699
 
700
        DBG("seeking...\n");
701
        if (MFM_DRV_INFO.cylinder < 0) {
702
                SET_INTR(mfm_recal_intr);
703
                DBG("mfm_seek: about to call specify\n");
704
                mfm_specify (); /* DAG added this */
705
 
706
                cmdb[0] = raw_cmd.dev + 1;
707
                cmdb[1] = 0;
708
 
709
                issue_command(CMD_RCLB, cmdb, 2);
710
                return;
711
        }
712
        if (MFM_DRV_INFO.cylinder != raw_cmd.cylinder) {
713
                cmdb[0] = raw_cmd.dev + 1;
714
                cmdb[1] = 0;     /* raw_cmd.head; DAG: My data sheet says this should be 0 */
715
                cmdb[2] = raw_cmd.cylinder >> 8;
716
                cmdb[3] = raw_cmd.cylinder;
717
 
718
                SET_INTR(mfm_seek_intr);
719
                issue_command(CMD_SEK, cmdb, 4);
720
        } else
721
                mfm_setup_rw();
722
}
723
 
724
static void mfm_initialise(void)
725
{
726
        DBG("init...\n");
727
        mfm_seek();
728
}
729
 
730
static void request_done(int uptodate)
731
{
732
        DBG("mfm:request_done\n");
733
        if (uptodate) {
734
                unsigned char block[2] = {0, 0};
735
 
736
                /* Apparently worked - lets check bytes left to DMA */
737
                if (hdc63463_dataleft != (PartFragRead_SectorsLeft * 256)) {
738
                        printk("mfm: request_done - dataleft=%d - should be %d - Eek!\n", hdc63463_dataleft, PartFragRead_SectorsLeft * 256);
739
                        end_request(0);
740
                        Busy = 0;
741
                };
742
                /* Potentially this means that we've done; but we might be doing
743
                   a partial access, (over two cylinders) or we may have a number
744
                   of fragments in an image file.  First lets deal with partial accesss
745
                 */
746
                if (PartFragRead) {
747
                        /* Yep - a partial access */
748
 
749
                        /* and issue the remainder */
750
                        issue_request(MINOR(CURRENT->rq_dev), PartFragRead_RestartBlock, PartFragRead_SectorsLeft, CURRENT);
751
                        return;
752
                }
753
 
754
                /* ah well - perhaps there is another fragment to go */
755
 
756
                /* Increment pointers/counts to start of next fragment */
757
                if (SectorsLeftInRequest > 0) printk("mfm: SectorsLeftInRequest>0 - Eek! Shouldn't happen!\n");
758
 
759
                /* No - its the end of the line */
760
                /* end_request's should have happened at the end of sector DMAs */
761
                /* Turns Drive LEDs off - may slow it down? */
762
                if (!CURRENT)
763
                        issue_command(CMD_CKV, block, 2);
764
 
765
                Busy = 0;
766
                DBG("request_done: About to mfm_request\n");
767
                /* Next one please */
768
                mfm_request();  /* Moved from mfm_rw_intr */
769
                DBG("request_done: returned from mfm_request\n");
770
        } else {
771
                printk("mfm:request_done: update=0\n");
772
                end_request(0);
773
                Busy = 0;
774
        }
775
}
776
 
777
static void error_handler(void)
778
{
779
        printk("error detected... status = ");
780
        print_status();
781
        (*errors)++;
782
        if (*errors > MFM_DRV_INFO.errors.abort)
783
                cont->done(0);
784
        if (*errors > MFM_DRV_INFO.errors.recal)
785
                MFM_DRV_INFO.cylinder = NEED_2_RECAL;
786
}
787
 
788
static void rw_interrupt(void)
789
{
790
        printk("rw_interrupt\n");
791
}
792
 
793
static struct cont rw_cont =
794
{
795
        rw_interrupt,
796
        error_handler,
797
        mfm_rerequest,
798
        request_done
799
};
800
 
801
/*
802
 * Actually gets round to issuing the request - note everything at this
803
 * point is in 256 byte sectors not Linux 512 byte blocks
804
 */
805
static void issue_request(int dev, unsigned int block, unsigned int nsect,
806
                          struct request *req)
807
{
808
        int track, start_head, start_sector;
809
        int sectors_to_next_cyl;
810
 
811
        dev >>= 6;
812
 
813
        track = block / mfm_info[dev].sectors;
814
        start_sector = block % mfm_info[dev].sectors;
815
        start_head = track % mfm_info[dev].heads;
816
 
817
        /* First get the number of whole tracks which are free before the next
818
           track */
819
        sectors_to_next_cyl = (mfm_info[dev].heads - (start_head + 1)) * mfm_info[dev].sectors;
820
        /* Then add in the number of sectors left on this track */
821
        sectors_to_next_cyl += (mfm_info[dev].sectors - start_sector);
822
 
823
        DBG("issue_request: mfm_info[dev].sectors=%d track=%d\n", mfm_info[dev].sectors, track);
824
 
825
        raw_cmd.dev = dev;
826
        raw_cmd.sector = start_sector;
827
        raw_cmd.head = start_head;
828
        raw_cmd.cylinder = track / mfm_info[dev].heads;
829
        raw_cmd.cmdtype = CURRENT->cmd;
830
        raw_cmd.cmdcode = CURRENT->cmd == WRITE ? CMD_WD : CMD_RD;
831
        raw_cmd.cmddata[0] = dev + 1;    /* DAG: +1 to get US */
832
        raw_cmd.cmddata[1] = raw_cmd.head;
833
        raw_cmd.cmddata[2] = raw_cmd.cylinder >> 8;
834
        raw_cmd.cmddata[3] = raw_cmd.cylinder;
835
        raw_cmd.cmddata[4] = raw_cmd.head;
836
        raw_cmd.cmddata[5] = raw_cmd.sector;
837
 
838
        /* Was == and worked - how the heck??? */
839
        if (lastspecifieddrive != raw_cmd.dev)
840
                mfm_specify ();
841
 
842
        if (nsect <= sectors_to_next_cyl) {
843
                raw_cmd.cmddata[6] = nsect >> 8;
844
                raw_cmd.cmddata[7] = nsect;
845
                PartFragRead = 0;        /* All in one */
846
                PartFragRead_SectorsLeft = 0;    /* Must set this - used in DMA calcs */
847
        } else {
848
                raw_cmd.cmddata[6] = sectors_to_next_cyl >> 8;
849
                raw_cmd.cmddata[7] = sectors_to_next_cyl;
850
                PartFragRead = sectors_to_next_cyl;     /* only do this many this time */
851
                PartFragRead_RestartBlock = block + sectors_to_next_cyl;        /* Where to restart from */
852
                PartFragRead_SectorsLeft = nsect - sectors_to_next_cyl;
853
        }
854
        raw_cmd.cmdlen = 8;
855
 
856
        /* Setup DMA pointers */
857
        hdc63463_dataptr = (unsigned int) Copy_buffer;
858
        hdc63463_dataleft = nsect * 256;        /* Better way? */
859
 
860
        DBG("mfm%c: %sing: CHS=%d/%d/%d, sectors=%d, buffer=0x%08lx (%p)\n",
861
             raw_cmd.dev + 'a', (CURRENT->cmd == READ) ? "read" : "writ",
862
                       raw_cmd.cylinder,
863
                       raw_cmd.head,
864
            raw_cmd.sector, nsect, (unsigned long) Copy_buffer, CURRENT);
865
 
866
        cont = &rw_cont;
867
        errors = &(CURRENT->errors);
868
#if 0
869
        mfm_tq.routine = (void (*)(void *)) mfm_initialise;
870
        queue_task(&mfm_tq, &tq_immediate);
871
        mark_bh(IMMEDIATE_BH);
872
#else
873
        mfm_initialise();
874
#endif
875
}                               /* issue_request */
876
 
877
/*
878
 * Called when an error has just happened - need to trick mfm_request
879
 * into thinking we weren't busy
880
 *
881
 * Turn off ints - mfm_request expects them this way
882
 */
883
static void mfm_rerequest(void)
884
{
885
        DBG("mfm_rerequest\n");
886
        cli();
887
        Busy = 0;
888
        mfm_request();
889
}
890
 
891
static void mfm_request(void)
892
{
893
        DBG("mfm_request CURRENT=%p Busy=%d\n", CURRENT, Busy);
894
 
895
        if (!CURRENT) {
896
                DBG("mfm_request: Exited due to NULL Current 1\n");
897
                return;
898
        }
899
 
900
        if (CURRENT->rq_status == RQ_INACTIVE) {
901
                /* Hmm - seems to be happening a lot on 1.3.45 */
902
                /*console_printf("mfm_request: Exited due to INACTIVE Current\n"); */
903
                return;
904
        }
905
 
906
        /* If we are still processing then return; we will get called again */
907
        if (Busy) {
908
                /* Again seems to be common in 1.3.45 */
909
                /*DBG*/printk("mfm_request: Exiting due to busy\n");
910
                return;
911
        }
912
        Busy = 1;
913
 
914
        while (1) {
915
                unsigned int dev, block, nsect;
916
 
917
                DBG("mfm_request: loop start\n");
918
                sti();
919
 
920
                DBG("mfm_request: before INIT_REQUEST\n");
921
 
922
                if (!CURRENT) {
923
                        printk("mfm_request: Exiting due to !CURRENT (pre)\n");
924
                        CLEAR_INTR;
925
                        Busy = 0;
926
                        return;
927
                };
928
 
929
                INIT_REQUEST;
930
 
931
                DBG("mfm_request:                 before arg extraction\n");
932
 
933
                dev = MINOR(CURRENT->rq_dev);
934
                block = CURRENT->sector;
935
                nsect = CURRENT->nr_sectors;
936
#ifdef DEBUG
937
                /*if ((dev>>6)==1) */ console_printf("mfm_request:                                raw vals: dev=%d (block=512 bytes) block=%d nblocks=%d\n", dev, block, nsect);
938
#endif
939
                if (dev >= (mfm_drives << 6) ||
940
                    block >= mfm[dev].nr_sects || ((block+nsect) > mfm[dev].nr_sects)) {
941
                        if (dev >= (mfm_drives << 6))
942
                                printk("mfm: bad minor number: device=%s\n", kdevname(CURRENT->rq_dev));
943
                        else
944
                                printk("mfm%c: bad access: block=%d, count=%d, nr_sects=%ld\n", (dev >> 6)+'a',
945
                                       block, nsect, mfm[dev].nr_sects);
946
                        printk("mfm: continue 1\n");
947
                        end_request(0);
948
                        Busy = 0;
949
                        continue;
950
                }
951
 
952
                block += mfm[dev].start_sect;
953
 
954
                /* DAG: Linux doesn't cope with this - even though it has an array telling
955
                   it the hardware block size - silly */
956
                block <<= 1;    /* Now in 256 byte sectors */
957
                nsect <<= 1;    /* Ditto */
958
 
959
                SectorsLeftInRequest = nsect >> 1;
960
                Sectors256LeftInCurrent = CURRENT->current_nr_sectors * 2;
961
                Copy_buffer = CURRENT->buffer;
962
                Copy_Sector = CURRENT->sector << 1;
963
 
964
                DBG("mfm_request: block after offset=%d\n", block);
965
 
966
                if (CURRENT->cmd != READ && CURRENT->cmd != WRITE) {
967
                        printk("unknown mfm-command %d\n", CURRENT->cmd);
968
                        end_request(0);
969
                        Busy = 0;
970
                        printk("mfm: continue 4\n");
971
                        continue;
972
                }
973
                issue_request(dev, block, nsect, CURRENT);
974
 
975
                break;
976
        }
977
        DBG("mfm_request: Dropping out bottom\n");
978
}
979
 
980
static void do_mfm_request(void)
981
{
982
        DBG("do_mfm_request: about to mfm_request\n");
983
        mfm_request();
984
}
985
 
986
static void mfm_interrupt_handler(int unused, void *dev_id, struct pt_regs *regs)
987
{
988
        void (*handler) (void) = DEVICE_INTR;
989
 
990
        CLEAR_INTR;
991
 
992
        DBG("mfm_interrupt_handler (handler=0x%p)\n", handler);
993
 
994
        mfm_status = inw(MFM_STATUS);
995
 
996
        /* If CPR (Command Parameter Reject) and not busy it means that the command
997
           has some return message to give us */
998
        if ((mfm_status & (STAT_CPR | STAT_BSY)) == STAT_CPR) {
999
                int len = 0;
1000
                while (len < 16) {
1001
                        int in;
1002
                        in = inw(MFM_DATAIN);
1003
                        result[len++] = in >> 8;
1004
                        result[len++] = in;
1005
                }
1006
        }
1007
        if (handler) {
1008
                handler();
1009
                return;
1010
        }
1011
        outw (CMD_RCAL, MFM_COMMAND);   /* Clear interrupt condition */
1012
        printk ("mfm: unexpected interrupt - status = ");
1013
        print_status ();
1014
        while (1);
1015
}
1016
 
1017
 
1018
 
1019
 
1020
 
1021
/*
1022
 * Tell the user about the drive if we decided it exists.  Also,
1023
 * set the size of the drive.
1024
 */
1025
static void mfm_geometry (int drive)
1026
{
1027
        if (mfm_info[drive].cylinders)
1028
                printk ("mfm%c: %dMB CHS=%d/%d/%d LCC=%d RECOMP=%d\n", 'a' + drive,
1029
                        mfm_info[drive].cylinders * mfm_info[drive].heads * mfm_info[drive].sectors / 4096,
1030
                        mfm_info[drive].cylinders, mfm_info[drive].heads, mfm_info[drive].sectors,
1031
                        mfm_info[drive].lowcurrent, mfm_info[drive].precomp);
1032
        mfm[drive << 6].start_sect = 0;
1033
        mfm[drive << 6].nr_sects = mfm_info[drive].cylinders * mfm_info[drive].heads * mfm_info[drive].sectors / 2;
1034
}
1035
 
1036
#ifdef MFM_AUTODETECT_DRIVES
1037
/*
1038
 * Attempt to detect a drive and find its geometry.  The drive has already been
1039
 * specified...
1040
 *
1041
 * We first recalibrate the disk, then try to probe sectors, heads and then
1042
 * cylinders.  NOTE! the cylinder probe may break drives.  The xd disk driver
1043
 * does something along these lines, so I assume that most drives are up to
1044
 * this mistreatment...
1045
 */
1046
static int mfm_detectdrive (int drive)
1047
{
1048
        unsigned int mingeo[3], maxgeo[3];
1049
        unsigned int attribute, need_recal = 1;
1050
        unsigned char cmdb[8];
1051
 
1052
        memset (mingeo, 0, sizeof (mingeo));
1053
        maxgeo[0] = mfm_info[drive].sectors;
1054
        maxgeo[1] = mfm_info[drive].heads;
1055
        maxgeo[2] = mfm_info[drive].cylinders;
1056
 
1057
        cmdb[0] = drive + 1;
1058
        cmdb[6] = 0;
1059
        cmdb[7] = 1;
1060
        for (attribute = 0; attribute < 3; attribute++) {
1061
                while (mingeo[attribute] != maxgeo[attribute]) {
1062
                        unsigned int variable;
1063
 
1064
                        variable = (maxgeo[attribute] + mingeo[attribute]) >> 1;
1065
                        cmdb[1] = cmdb[2] = cmdb[3] = cmdb[4] = cmdb[5] = 0;
1066
 
1067
                        if (need_recal) {
1068
                                int tries = 5;
1069
 
1070
                                do {
1071
                                        issue_command (CMD_RCLB, cmdb, 2);
1072
                                        wait_for_completion ();
1073
                                        wait_for_command_end ();
1074
                                        if  (result[1] == 0x20)
1075
                                                break;
1076
                                } while (result[1] && --tries);
1077
                                if (result[1]) {
1078
                                        outw (CMD_RCAL, MFM_COMMAND);
1079
                                        return 0;
1080
                                }
1081
                                need_recal = 0;
1082
                        }
1083
 
1084
                        switch (attribute) {
1085
                        case 0:
1086
                                cmdb[5] = variable;
1087
                                issue_command (CMD_CMPD, cmdb, 8);
1088
                                break;
1089
                        case 1:
1090
                                cmdb[1] = variable;
1091
                                cmdb[4] = variable;
1092
                                issue_command (CMD_CMPD, cmdb, 8);
1093
                                break;
1094
                        case 2:
1095
                                cmdb[2] = variable >> 8;
1096
                                cmdb[3] = variable;
1097
                                issue_command (CMD_SEK, cmdb, 4);
1098
                                break;
1099
                        }
1100
                        wait_for_completion ();
1101
                        wait_for_command_end ();
1102
 
1103
                        switch (result[1]) {
1104
                        case 0x00:
1105
                        case 0x50:
1106
                                mingeo[attribute] = variable + 1;
1107
                                break;
1108
 
1109
                        case 0x20:
1110
                                outw (CMD_RCAL, MFM_COMMAND);
1111
                                return 0;
1112
 
1113
                        case 0x24:
1114
                                need_recal = 1;
1115
                        default:
1116
                                maxgeo[attribute] = variable;
1117
                                break;
1118
                        }
1119
                }
1120
        }
1121
        mfm_info[drive].cylinders  = mingeo[2];
1122
        mfm_info[drive].lowcurrent = mingeo[2];
1123
        mfm_info[drive].precomp    = mingeo[2] / 2;
1124
        mfm_info[drive].heads      = mingeo[1];
1125
        mfm_info[drive].sectors    = mingeo[0];
1126
        outw (CMD_RCAL, MFM_COMMAND);
1127
        return 1;
1128
}
1129
#endif
1130
 
1131
/*
1132
 * Initialise all drive information for this controller.
1133
 */
1134
static int mfm_initdrives(void)
1135
{
1136
        int drive;
1137
 
1138
        if (number_mfm_drives > MFM_MAXDRIVES) {
1139
                number_mfm_drives = MFM_MAXDRIVES;
1140
                printk("No. of ADFS MFM drives is greater than MFM_MAXDRIVES - you can't have that many!\n");
1141
        }
1142
 
1143
        for (drive = 0; drive < number_mfm_drives; drive++) {
1144
                mfm_info[drive].lowcurrent = 1;
1145
                mfm_info[drive].precomp    = 1;
1146
                mfm_info[drive].cylinder   = -1;
1147
                mfm_info[drive].errors.recal  = 0;
1148
                mfm_info[drive].errors.report = 0;
1149
                mfm_info[drive].errors.abort  = 4;
1150
 
1151
#ifdef MFM_AUTODETECT_DRIVES
1152
                mfm_info[drive].cylinders  = 1024;
1153
                mfm_info[drive].heads      = 8;
1154
                mfm_info[drive].sectors    = 64;
1155
                {
1156
                        unsigned char cmdb[16];
1157
 
1158
                        mfm_setupspecify (drive, cmdb);
1159
                        cmdb[1] &= ~0x81;
1160
                        issue_command (CMD_SPC, cmdb, 16);
1161
                        wait_for_completion ();
1162
                        if (!mfm_detectdrive (drive)) {
1163
                                mfm_info[drive].cylinders = 0;
1164
                                mfm_info[drive].heads     = 0;
1165
                                mfm_info[drive].sectors   = 0;
1166
                        }
1167
                        cmdb[0] = cmdb[1] = 0;
1168
                        issue_command (CMD_CKV, cmdb, 2);
1169
                }
1170
#else
1171
                mfm_info[drive].cylinders  = 1; /* its going to have to figure it out from the partition info */
1172
                mfm_info[drive].heads      = 4;
1173
                mfm_info[drive].sectors    = 32;
1174
#endif
1175
        }
1176
        return number_mfm_drives;
1177
}
1178
 
1179
 
1180
 
1181
/*
1182
 * The 'front' end of the mfm driver follows...
1183
 */
1184
 
1185
static int mfm_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg)
1186
{
1187
        struct hd_geometry *geo = (struct hd_geometry *) arg;
1188
        int dev, err;
1189
 
1190
        if (!inode || !inode->i_rdev)
1191
                return -EINVAL;
1192
        dev = DEVICE_NR(MINOR(inode->i_rdev)), err;
1193
        if (dev >= mfm_drives)
1194
                return -EINVAL;
1195
 
1196
        switch (cmd) {
1197
        case HDIO_GETGEO:
1198
                if (!arg)
1199
                        return -EINVAL;
1200
                err = verify_area (VERIFY_WRITE, geo, sizeof(*geo));
1201
                if (err)
1202
                        return err;
1203
                put_user (mfm_info[dev].heads, &geo->heads);
1204
                put_user (mfm_info[dev].sectors, &geo->sectors);
1205
                put_user (mfm_info[dev].cylinders, &geo->cylinders);
1206
                put_user (mfm[MINOR(inode->i_rdev)].start_sect, &geo->start);
1207
                return 0;
1208
 
1209
        case BLKRASET:
1210
                if (!suser())
1211
                        return -EACCES;
1212
                if (arg > 0xff)
1213
                        return -EINVAL;
1214
                read_ahead[MAJOR(inode->i_rdev)] = arg;
1215
                return 0;
1216
 
1217
        case BLKRAGET:
1218
                if (!arg)
1219
                        return -EINVAL;
1220
                err = verify_area (VERIFY_WRITE, (long *) arg, sizeof (long));
1221
                if (err)
1222
                        return err;
1223
                put_user(read_ahead[MAJOR(inode->i_rdev)], (long *)arg);
1224
                return 0;
1225
 
1226
        case BLKGETSIZE:
1227
                if (!arg)
1228
                        return -EINVAL;
1229
                err = verify_area (VERIFY_WRITE, (long *) arg, sizeof (long));
1230
                if (err)
1231
                         return err;
1232
                put_user (mfm[MINOR(inode->i_rdev)].nr_sects, (long *)arg);
1233
                return 0;
1234
 
1235
        case BLKFLSBUF:
1236
                if (!suser())
1237
                        return -EACCES;
1238
                if (!inode->i_rdev)
1239
                        return -EINVAL;
1240
                fsync_dev(inode->i_rdev);
1241
                invalidate_buffers(inode->i_rdev);
1242
                return 0;
1243
 
1244
        case BLKRRPART:
1245
                return mfm_reread_partitions(inode->i_rdev);
1246
 
1247
        RO_IOCTLS(inode->i_rdev, arg);
1248
        default:
1249
                return -EINVAL;
1250
        }
1251
}
1252
 
1253
static int mfm_open(struct inode *inode, struct file *file)
1254
{
1255
        int dev = DEVICE_NR(MINOR(inode->i_rdev));
1256
 
1257
        if (dev >= mfm_drives)
1258
                return -ENODEV;
1259
        while (mfm_info[dev].busy)
1260
                sleep_on (&mfm_wait_open);
1261
        mfm_info[dev].access_count++;
1262
        return 0;
1263
}
1264
 
1265
/*
1266
 * Releasing a block device means we sync() it, so that it can safely
1267
 * be forgotten about...
1268
 */
1269
static void mfm_release(struct inode *inode, struct file *file)
1270
{
1271
        sync_dev(inode->i_rdev);
1272
        mfm_info[DEVICE_NR(MINOR(inode->i_rdev))].access_count--;
1273
}
1274
 
1275
/*
1276
 * This is to handle various kernel command line parameters
1277
 * specific to this driver.
1278
 */
1279
void mfm_setup(char *str, int *ints)
1280
{
1281
        return;
1282
}
1283
 
1284
/*
1285
 * Set the CHS from the ADFS boot block if it is present.  This is not ideal
1286
 * since if there are any non-ADFS partitions on the disk, this won't work!
1287
 * Hence, I want to get rid of this...
1288
 */
1289
void xd_set_geometry(kdev_t dev, unsigned char secsptrack, unsigned char heads,
1290
                     unsigned long discsize, unsigned int secsize)
1291
{
1292
        int drive = MINOR(dev) >> 6;
1293
 
1294
        if (mfm_info[drive].cylinders == 1) {
1295
                mfm_info[drive].sectors = secsptrack;
1296
                mfm_info[drive].heads = heads;
1297
                mfm_info[drive].cylinders = discsize / (secsptrack * heads * secsize);
1298
 
1299
                if ((heads < 1) || (mfm_info[drive].cylinders > 1024)) {
1300
                        printk("mfm%c: Insane disc shape! Setting to 512/4/32\n",'a' + (dev >> 6));
1301
 
1302
                        /* These values are fairly arbitary, but are there so that if your
1303
                         * lucky you can pick apart your disc to find out what is going on -
1304
                         * I reckon these figures won't hurt MOST drives
1305
                         */
1306
                        mfm_info[drive].sectors = 32;
1307
                        mfm_info[drive].heads = 4;
1308
                        mfm_info[drive].cylinders = 512;
1309
                }
1310
                if (raw_cmd.dev == drive)
1311
                        mfm_specify ();
1312
                mfm_geometry (drive);
1313
        }
1314
}
1315
 
1316
static void mfm_geninit (struct gendisk *gdev);
1317
 
1318
static struct gendisk mfm_gendisk = {
1319
        MAJOR_NR,               /* Major number */
1320
        "mfm",                  /* Major name */
1321
        6,                      /* Bits to shift to get real from partition */
1322
        1 << 6,                 /* Number of partitions per real */
1323
        MFM_MAXDRIVES,          /* maximum number of real */
1324
        mfm_geninit,            /* init function */
1325
        mfm,                    /* hd struct */
1326
        mfm_sizes,              /* block sizes */
1327
        0,                       /* number */
1328
        (void *) mfm_info,      /* internal */
1329
        NULL                    /* next */
1330
};
1331
 
1332
static void mfm_geninit (struct gendisk *gdev)
1333
{
1334
        int i;
1335
 
1336
        mfm_drives = mfm_initdrives();
1337
 
1338
        printk("mfm: detected %d hard drive%s\n", mfm_drives, mfm_drives == 1 ? "" : "s");
1339
        gdev->nr_real = mfm_drives;
1340
 
1341
        for (i = 0; i < mfm_drives; i++)
1342
                mfm_geometry (i);
1343
 
1344
        if (request_irq(mfm_irq, mfm_interrupt_handler, SA_INTERRUPT, "MFM harddisk", NULL))
1345
                printk("mfm: unable to get IRQ%d\n", mfm_irq);
1346
 
1347
        if (mfm_irqenable)
1348
                outw(0x80, mfm_irqenable);      /* Required to enable IRQs from MFM podule */
1349
 
1350
        for (i = 0; i < (MFM_MAXDRIVES << 6); i++) {
1351
                mfm_blocksizes[i] = 1024;       /* Can't increase this - if you do all hell breaks loose */
1352
                mfm_sectsizes[i] = 512;
1353
        }
1354
        blksize_size[MAJOR_NR] = mfm_blocksizes;
1355
        hardsect_size[MAJOR_NR] = mfm_sectsizes;
1356
}
1357
 
1358
void xd_manual_geo_init (char *command,int *integers) {
1359
  printk("MFM:Manual setting of geometry not presently supported\n");
1360
}
1361
 
1362
static struct file_operations mfm_fops =
1363
{
1364
        NULL,                   /* lseek - default */
1365
        block_read,             /* read - general block-dev read */
1366
        block_write,            /* write - general block-dev write */
1367
        NULL,                   /* readdir - bad */
1368
        NULL,                   /* select */
1369
        mfm_ioctl,              /* ioctl */
1370
        NULL,                   /* mmap */
1371
        mfm_open,               /* open */
1372
        mfm_release,            /* release */
1373
        block_fsync             /* fsync */
1374
};
1375
 
1376
 
1377
static struct expansion_card *ecs;
1378
 
1379
/*
1380
 * See if there is a controller at the address presently at mfm_addr
1381
 *
1382
 * We check to see if the controller is busy - if it is, we abort it first,
1383
 * and check that the chip is no longer busy after at least 180 clock cycles.
1384
 * We then issue a command and check that the BSY or CPR bits are set.
1385
 */
1386
static int mfm_probecontroller (unsigned int mfm_addr)
1387
{
1388
        if (check_region (mfm_addr, 10))
1389
                return 0;
1390
 
1391
        if (inw (MFM_STATUS) & STAT_BSY) {
1392
                outw (CMD_ABT, MFM_COMMAND);
1393
                udelay (50);
1394
                if (inw (MFM_STATUS) & STAT_BSY)
1395
                        return 0;
1396
        }
1397
 
1398
        if (inw (MFM_STATUS) & STAT_CED)
1399
                outw (CMD_RCAL, MFM_COMMAND);
1400
 
1401
        outw (CMD_SEK, MFM_COMMAND);
1402
 
1403
        if (inw (MFM_STATUS) & (STAT_BSY | STAT_CPR)) {
1404
                unsigned int count = 2000;
1405
                while (inw (MFM_STATUS) & STAT_BSY) {
1406
                        udelay (500);
1407
                        if (!--count)
1408
                                return 0;
1409
                }
1410
 
1411
                outw (CMD_RCAL, MFM_COMMAND);
1412
        }
1413
        return 1;
1414
}
1415
 
1416
/*
1417
 * Look for a MFM controller - first check the motherboard, then the podules
1418
 * The podules have an extra interrupt enable that needs to be played with
1419
 *
1420
 * The HDC is accessed at MEDIUM IOC speeds.
1421
 */
1422
int mfm_init (void)
1423
{
1424
        unsigned char irqmask;
1425
 
1426
        if (register_blkdev(MAJOR_NR, "mfm", &mfm_fops)) {
1427
                printk("mfm_init: unable to get major number %d\n", MAJOR_NR);
1428
                return -1;
1429
        }
1430
 
1431
        if (mfm_probecontroller(ONBOARD_MFM_ADDRESS)) {
1432
                mfm_addr        = ONBOARD_MFM_ADDRESS;
1433
                mfm_IRQPollLoc  = IOC_IRQSTATB;
1434
                mfm_irqenable   = 0;
1435
                mfm_irq         = IRQ_HARDDISK;
1436
                irqmask         = 0x08;                 /* IL3 pin */
1437
        } else {
1438
                ecs = ecard_find(0, mfm_cids);
1439
                if (!ecs) {
1440
                        mfm_addr = 0;
1441
                        return -1;
1442
                }
1443
 
1444
                mfm_addr        = ecard_address(ecs, ECARD_IOC, ECARD_MEDIUM) + 0x800;
1445
                mfm_IRQPollLoc  = mfm_addr + 0x400;
1446
                mfm_irqenable   = mfm_IRQPollLoc;
1447
                mfm_irq         = ecs->irq;
1448
                irqmask         = 0x08;
1449
 
1450
                ecard_claim(ecs);
1451
        }
1452
 
1453
        printk("mfm: found at address %08X, interrupt %d\n", mfm_addr, mfm_irq);
1454
        request_region (mfm_addr, 10, "mfm");
1455
 
1456
        /* Stuff for the assembler routines to get to */
1457
        hdc63463_baseaddress    = ioaddr(mfm_addr);
1458
        hdc63463_irqpolladdress = ioaddr(mfm_IRQPollLoc);
1459
        hdc63463_irqpollmask    = irqmask;
1460
 
1461
        blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
1462
        read_ahead[MAJOR_NR] = 8;       /* 8 sector (4kB?) read ahread */
1463
 
1464
#ifndef MODULE
1465
        mfm_gendisk.next = gendisk_head;
1466
        gendisk_head = &mfm_gendisk;
1467
#endif
1468
 
1469
        Busy = 0;
1470
        lastspecifieddrive = -1;
1471
 
1472
        return 0;
1473
}
1474
 
1475
/*
1476
 * This routine is called to flush all partitions and partition tables
1477
 * for a changed MFM disk, and then re-read the new partition table.
1478
 * If we are revalidating due to an ioctl, we have USAGE == 1.
1479
 */
1480
static int mfm_reread_partitions(kdev_t dev)
1481
{
1482
        unsigned int start, i, maxp, target = DEVICE_NR(MINOR(dev));
1483
        unsigned long flags;
1484
 
1485
        save_flags_cli(flags);
1486
        if (mfm_info[target].busy || mfm_info[target].access_count > 1) {
1487
                restore_flags (flags);
1488
                return -EBUSY;
1489
        }
1490
        mfm_info[target].busy = 1;
1491
        restore_flags (flags);
1492
 
1493
        maxp = mfm_gendisk.max_p;
1494
        start = target << mfm_gendisk.minor_shift;
1495
 
1496
        for (i = maxp - 1; i >= 0; i--) {
1497
                int minor = start + i;
1498
                kdev_t devi = MKDEV(MAJOR_NR, minor);
1499
 
1500
                sync_dev (devi);
1501
                invalidate_inodes (devi);
1502
                invalidate_buffers (devi);
1503
 
1504
                mfm_gendisk.part[minor].start_sect = 0;
1505
                mfm_gendisk.part[minor].nr_sects = 0;
1506
        }
1507
 
1508
        mfm_gendisk.part[start].nr_sects = mfm_info[target].heads *
1509
            mfm_info[target].cylinders * mfm_info[target].sectors / 2;
1510
 
1511
        resetup_one_dev(&mfm_gendisk, target);
1512
 
1513
        mfm_info[target].busy = 0;
1514
        wake_up (&mfm_wait_open);
1515
        return 0;
1516
}
1517
 
1518
#ifdef MODULE
1519
int init_module(void)
1520
{
1521
        int ret;
1522
        ret = mfm_init();
1523
        if (!ret)
1524
                mfm_geninit(&mfm_gendisk);
1525
        return ret;
1526
}
1527
 
1528
void cleanup_module(void)
1529
{
1530
        if (ecs && mfm_irqenable)
1531
                outw (0, mfm_irqenable); /* Required to enable IRQs from MFM podule */
1532
        free_irq(mfm_irq, NULL);
1533
        unregister_blkdev(MAJOR_NR, "mfm");
1534
        if (ecs)
1535
                ecard_release(ecs);
1536
        if (mfm_addr)
1537
                release_region(mfm_addr, 10);
1538
}
1539
#endif

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.