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