Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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