root/kernel/blk_drv/hd.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. CMOS_READ
  2. read_timer
  3. controller_ready
  4. win_result
  5. hd_out
  6. drive_busy
  7. reset_controller
  8. reset_hd
  9. unexpected_hd_interrupt
  10. bad_rw_intr
  11. wait_DRQ
  12. read_intr
  13. write_intr
  14. recal_intr
  15. hd_times_out
  16. do_hd_request
  17. hd_ioctl
  18. hd_release
  19. hd_geninit
  20. hd_interrupt
  21. hd_init

   1 /*
   2  *  linux/kernel/hd.c
   3  *
   4  *  Copyright (C) 1991, 1992  Linus Torvalds
   5  */
   6 
   7 /*
   8  * This is the low-level hd interrupt support. It traverses the
   9  * request-list, using interrupts to jump between functions. As
  10  * all the functions are called within interrupts, we may not
  11  * sleep. Special care is recommended.
  12  * 
  13  *  modified by Drew Eckhardt to check nr of hd's from the CMOS.
  14  *
  15  *  Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
  16  *  in the early extended-partition checks and added DM partitions
  17  */
  18 
  19 #include <linux/config.h>
  20 #ifdef CONFIG_BLK_DEV_HD
  21 
  22 #define HD_IRQ 14
  23 
  24 #include <linux/errno.h>
  25 #include <linux/signal.h>
  26 #include <linux/sched.h>
  27 #include <linux/timer.h>
  28 #include <linux/fs.h>
  29 #include <linux/kernel.h>
  30 #include <linux/hdreg.h>
  31 #include <linux/genhd.h>
  32 
  33 #define REALLY_SLOW_IO
  34 #include <asm/system.h>
  35 #include <asm/io.h>
  36 #include <asm/segment.h>
  37 
  38 #define MAJOR_NR 3
  39 #include "blk.h"
  40 
  41 static inline unsigned char CMOS_READ(unsigned char addr)
     /* [previous][next][first][last][top][bottom][index][help] */
  42 {
  43         outb_p(0x80|addr,0x70);
  44         return inb_p(0x71);
  45 }
  46 
  47 #define HD_DELAY        0
  48 
  49 /* Max read/write errors/sector */
  50 #define MAX_ERRORS      7
  51 #define MAX_HD          2
  52 
  53 static void recal_intr(void);
  54 static void bad_rw_intr(void);
  55 
  56 static int recalibrate = 0;
  57 static int reset = 0;
  58 
  59 #if (HD_DELAY > 0)
  60 unsigned long last_req, read_timer();
  61 #endif
  62 
  63 /*
  64  *  This struct defines the HD's and their types.
  65  */
  66 struct hd_i_struct {
  67         unsigned int head,sect,cyl,wpcom,lzone,ctl;
  68         };
  69 #ifdef HD_TYPE
  70 struct hd_i_struct hd_info[] = { HD_TYPE };
  71 #define NR_HD ((sizeof (hd_info))/(sizeof (struct hd_i_struct)))
  72 #else
  73 struct hd_i_struct hd_info[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} };
  74 static int NR_HD = 0;
  75 #endif
  76 
  77 static struct hd_struct hd[MAX_HD<<6]={{0,0},};
  78 static int hd_sizes[MAX_HD<<6] = {0, };
  79 
  80 #define port_read(port,buf,nr) \
  81 __asm__("cld;rep;insw"::"d" (port),"D" (buf),"c" (nr):"cx","di")
  82 
  83 #define port_write(port,buf,nr) \
  84 __asm__("cld;rep;outsw"::"d" (port),"S" (buf),"c" (nr):"cx","si")
  85 
  86 #if (HD_DELAY > 0)
  87 unsigned long read_timer(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  88 {
  89         unsigned long t;
  90         int i;
  91 
  92         cli();
  93         outb_p(0xc2, 0x43);
  94         t = jiffies * 11931 + (inb_p(0x40) & 0x80 ? 5966 : 11932);
  95         i = inb_p(0x40);
  96         i |= inb(0x40) << 8;
  97         sti();
  98         return(t - i / 2);
  99 }
 100 #endif
 101 
 102 static int controller_ready(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 103 {
 104         int retries = 100000;
 105 
 106         while (--retries && (inb_p(HD_STATUS)&0x80))
 107                 /* nothing */;
 108         if (!retries)
 109                 printk("controller_ready: status = %02x\n\r",
 110                         (unsigned char) inb_p(HD_STATUS));
 111         return (retries);
 112 }
 113 
 114 static int win_result(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 115 {
 116         int i=inb_p(HD_STATUS);
 117 
 118         if ((i & (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT))
 119                 == (READY_STAT | SEEK_STAT))
 120                 return 0; /* ok */
 121         printk("HD: win_result: status = 0x%02x\n",i);
 122         if (i&1) {
 123                 i=inb(HD_ERROR);
 124                 printk("HD: win_result: error = 0x%02x\n",i);
 125         }       
 126         return 1;
 127 }
 128 
 129 static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
     /* [previous][next][first][last][top][bottom][index][help] */
 130                 unsigned int head,unsigned int cyl,unsigned int cmd,
 131                 void (*intr_addr)(void))
 132 {
 133         unsigned short port;
 134 
 135         if (drive>1 || head>15)
 136                 panic("Trying to write bad sector");
 137 #if (HD_DELAY > 0)
 138         while (read_timer() - last_req < HD_DELAY)
 139                 /* nothing */;
 140 #endif
 141         if (reset || !controller_ready()) {
 142                 reset = 1;
 143                 return;
 144         }
 145         SET_INTR(intr_addr);
 146         outb_p(hd_info[drive].ctl,HD_CMD);
 147         port=HD_DATA;
 148         outb_p(hd_info[drive].wpcom>>2,++port);
 149         outb_p(nsect,++port);
 150         outb_p(sect,++port);
 151         outb_p(cyl,++port);
 152         outb_p(cyl>>8,++port);
 153         outb_p(0xA0|(drive<<4)|head,++port);
 154         outb_p(cmd,++port);
 155 }
 156 
 157 static int drive_busy(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 158 {
 159         unsigned int i;
 160         unsigned char c;
 161 
 162         for (i = 0; i < 500000 ; i++) {
 163                 c = inb_p(HD_STATUS);
 164                 c &= (BUSY_STAT | READY_STAT | SEEK_STAT);
 165                 if (c == (READY_STAT | SEEK_STAT))
 166                         return 0;
 167         }
 168         printk("HD controller times out, status = 0x%02x\n\r",c);
 169         return(1);
 170 }
 171 
 172 static void reset_controller(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 173 {
 174         int     i;
 175 
 176         printk("HD-controller reset\r\n");
 177         outb(4,HD_CMD);
 178         for(i = 0; i < 1000; i++) nop();
 179         outb(hd_info[0].ctl & 0x0f ,HD_CMD);
 180         if (drive_busy())
 181                 printk("HD-controller still busy\n\r");
 182         if ((i = inb(HD_ERROR)) != 1)
 183                 printk("HD-controller reset failed: %02x\n\r",i);
 184 }
 185 
 186 static void reset_hd(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 187 {
 188         static int i;
 189 
 190 repeat:
 191         if (reset) {
 192                 reset = 0;
 193                 i = -1;
 194                 reset_controller();
 195         } else if (win_result()) {
 196                 bad_rw_intr();
 197                 if (reset)
 198                         goto repeat;
 199         }
 200         i++;
 201         if (i < NR_HD) {
 202                 hd_out(i,hd_info[i].sect,hd_info[i].sect,hd_info[i].head-1,
 203                         hd_info[i].cyl,WIN_SPECIFY,&reset_hd);
 204                 if (reset)
 205                         goto repeat;
 206         } else
 207                 do_hd_request();
 208 }
 209 
 210 /*
 211  * Ok, don't know what to do with the unexpected interrupts: on some machines
 212  * doing a reset and a retry seems to result in an eternal loop. Right now I
 213  * ignore it, and just set the timeout.
 214  */
 215 void unexpected_hd_interrupt(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 216 {
 217         sti();
 218         printk("Unexpected HD interrupt\n\r");
 219         SET_TIMER;
 220 }
 221 
 222 static void bad_rw_intr(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 223 {
 224         if (!CURRENT)
 225                 return;
 226         if (++CURRENT->errors >= MAX_ERRORS)
 227                 end_request(0);
 228         else if (CURRENT->errors > MAX_ERRORS/2)
 229                 reset = 1;
 230         else
 231                 recalibrate = 1;
 232 }
 233 
 234 static inline int wait_DRQ(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 235 {
 236         int retries = 100000;
 237 
 238         while (--retries > 0)
 239                 if (inb_p(HD_STATUS) & DRQ_STAT)
 240                         return 0;
 241         return -1;
 242 }
 243 
 244 #define STAT_MASK (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT)
 245 #define STAT_OK (READY_STAT | SEEK_STAT)
 246 
 247 static void read_intr(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 248 {
 249         int i;
 250 
 251         i = (unsigned) inb_p(HD_STATUS);
 252         if ((i & STAT_MASK) != STAT_OK) {
 253                 printk("HD: read_intr: status = 0x%02x\n",i);
 254                 goto bad_read;
 255         }
 256         if (wait_DRQ()) {
 257                 printk("HD: read_intr: no DRQ\n");
 258                 goto bad_read;
 259         }
 260         port_read(HD_DATA,CURRENT->buffer,256);
 261         i = (unsigned) inb_p(HD_STATUS);
 262         if (!(i & BUSY_STAT))
 263                 if ((i & STAT_MASK) != STAT_OK) {
 264                         printk("HD: read_intr: second status = 0x%02x\n",i);
 265                         goto bad_read;
 266                 }
 267         CURRENT->errors = 0;
 268         CURRENT->buffer += 512;
 269         CURRENT->sector++;
 270         i = --CURRENT->nr_sectors;
 271         --CURRENT->current_nr_sectors;
 272 #ifdef DEBUG
 273         printk("hd%d : sector = %d, %d remaining to buffer = %08x\n",
 274                 MINOR(CURRENT->dev), CURRENT->sector, i, CURRENT-> 
 275                 buffer);
 276 #endif
 277         if (!i || (CURRENT->bh && !SUBSECTOR(i)))
 278                 end_request(1);
 279         if (i > 0) {
 280                 SET_INTR(&read_intr);
 281                 sti();
 282                 return;
 283         }
 284 #if (HD_DELAY > 0)
 285         last_req = read_timer();
 286 #endif
 287         do_hd_request();
 288         return;
 289 bad_read:
 290         if (i & ERR_STAT) {
 291                 i = (unsigned) inb(HD_ERROR);
 292                 printk("HD: read_intr: error = 0x%02x\n",i);
 293         }
 294         bad_rw_intr();
 295         do_hd_request();
 296         return;
 297 }
 298 
 299 static void write_intr(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 300 {
 301         int i;
 302 
 303         i = (unsigned) inb_p(HD_STATUS);
 304         if ((i & STAT_MASK) != STAT_OK) {
 305                 printk("HD: write_intr: status = 0x%02x\n",i);
 306                 goto bad_write;
 307         }
 308         if (CURRENT->nr_sectors > 1 && wait_DRQ()) {
 309                 printk("HD: write_intr: no DRQ\n");
 310                 goto bad_write;
 311         }
 312         CURRENT->sector++;
 313         i = --CURRENT->nr_sectors;
 314         --CURRENT->current_nr_sectors;
 315         CURRENT->buffer += 512;
 316         if (!i || (CURRENT->bh && !SUBSECTOR(i)))
 317                 end_request(1);
 318         if (i > 0) {
 319                 SET_INTR(&write_intr);
 320                 port_write(HD_DATA,CURRENT->buffer,256);
 321                 sti();
 322         } else {
 323 #if (HD_DELAY > 0)
 324                 last_req = read_timer();
 325 #endif
 326                 do_hd_request();
 327         }
 328         return;
 329 bad_write:
 330         sti();
 331         if (i & ERR_STAT) {
 332                 i = (unsigned) inb(HD_ERROR);
 333                 printk("HD: write_intr: error = 0x%02x\n",i);
 334         }
 335         bad_rw_intr();
 336         cli();
 337         do_hd_request();
 338         return;
 339 }
 340 
 341 static void recal_intr(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 342 {
 343         if (win_result())
 344                 bad_rw_intr();
 345         do_hd_request();
 346 }
 347 
 348 /*
 349  * This is another of the error-routines I don't know what to do with. The
 350  * best idea seems to just set reset, and start all over again.
 351  */
 352 static void hd_times_out(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 353 {
 354         sti();
 355         DEVICE_INTR = NULL;
 356         reset = 1;
 357         if (!CURRENT)
 358                 return;
 359         printk("HD timeout\n\r");
 360         cli();
 361         if (++CURRENT->errors >= MAX_ERRORS) {
 362 #ifdef DEBUG
 363                 printk("hd : too many errors.\n");
 364 #endif
 365                 end_request(0);
 366         }
 367 
 368         do_hd_request();
 369 }
 370 
 371 /*
 372  * The driver has been modified to enable interrupts a bit more: in order to
 373  * do this we first (a) disable the timeout-interrupt and (b) clear the
 374  * device-interrupt. This way the interrupts won't mess with out code (the
 375  * worst that can happen is that an unexpected HD-interrupt comes in and
 376  * sets the "reset" variable and starts the timer)
 377  */
 378 static void do_hd_request(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 379 {
 380         unsigned int block,dev;
 381         unsigned int sec,head,cyl;
 382         unsigned int nsect;
 383 
 384 repeat:
 385         DEVICE_INTR = NULL;
 386         timer_active &= ~(1<<HD_TIMER);
 387         sti();
 388         INIT_REQUEST;
 389         dev = MINOR(CURRENT->dev);
 390         block = CURRENT->sector;
 391         nsect = CURRENT->nr_sectors;
 392         if (dev >= (NR_HD<<6) || block >= hd[dev].nr_sects) {
 393 #ifdef DEBUG
 394                 printk("hd%d : attempted read for sector %d past end of device at sector %d.\n",
 395                         block, hd[dev].nr_sects);
 396 #endif
 397                 end_request(0);
 398                 goto repeat;
 399         }
 400         block += hd[dev].start_sect;
 401         dev >>= 6;
 402         sec = block % hd_info[dev].sect;
 403         block /= hd_info[dev].sect;
 404         head = block % hd_info[dev].head;
 405         cyl = block / hd_info[dev].head;
 406         sec++;
 407 #ifdef DEBUG
 408         printk("hd%d : cyl = %d, head = %d, sector = %d, buffer = %08x\n",
 409                 dev, cyl, head, sec, CURRENT->buffer);
 410 #endif
 411         cli();
 412         if (reset) {
 413                 recalibrate = 1;
 414                 reset_hd();
 415                 sti();
 416                 return;
 417         }
 418         if (recalibrate) {
 419                 recalibrate = 0;
 420                 hd_out(dev,hd_info[dev].sect,0,0,0,WIN_RESTORE,&recal_intr);
 421                 if (reset)
 422                         goto repeat;
 423                 sti();
 424                 return;
 425         }       
 426         if (CURRENT->cmd == WRITE) {
 427                 hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
 428                 if (reset)
 429                         goto repeat;
 430                 if (wait_DRQ()) {
 431                         printk("HD: do_hd_request: no DRQ\n");
 432                         bad_rw_intr();
 433                         goto repeat;
 434                 }
 435                 port_write(HD_DATA,CURRENT->buffer,256);
 436                 sti();
 437         } else if (CURRENT->cmd == READ) {
 438                 hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr);
 439                 if (reset)
 440                         goto repeat;
 441                 sti();
 442         } else
 443                 panic("unknown hd-command");
 444 }
 445 
 446 static int hd_ioctl(struct inode * inode, struct file * file,
     /* [previous][next][first][last][top][bottom][index][help] */
 447         unsigned int cmd, unsigned int arg)
 448 {
 449         struct hd_geometry *loc = (void *) arg;
 450         int dev;
 451 
 452         if (!loc || !inode)
 453                 return -EINVAL;
 454         dev = MINOR(inode->i_rdev) >> 6;
 455         if (dev >= NR_HD)
 456                 return -EINVAL;
 457         switch (cmd) {
 458                 case HDIO_REQ:
 459                         verify_area(loc, sizeof(*loc));
 460                         put_fs_byte(hd_info[dev].head,
 461                                 (char *) &loc->heads);
 462                         put_fs_byte(hd_info[dev].sect,
 463                                 (char *) &loc->sectors);
 464                         put_fs_word(hd_info[dev].cyl,
 465                                 (short *) &loc->cylinders);
 466                         put_fs_long(hd[MINOR(inode->i_rdev)].start_sect,
 467                                 (long *) &loc->start);
 468                         return 0;
 469                 RO_IOCTLS(inode->i_rdev,arg);
 470                 default:
 471                         return -EINVAL;
 472         }
 473 }
 474 
 475 /*
 476  * Releasing a block device means we sync() it, so that it can safely
 477  * be forgotten about...
 478  */
 479 static void hd_release(struct inode * inode, struct file * file)
     /* [previous][next][first][last][top][bottom][index][help] */
 480 {
 481         sync_dev(inode->i_rdev);
 482 }
 483 
 484 
 485 static void hd_geninit();
 486 
 487 static struct gendisk hd_gendisk = {
 488         MAJOR_NR,       /* Major number */      
 489         "hd",           /* Major name */
 490         6,              /* Bits to shift to get real from partition */
 491         1 << 6,         /* Number of partitions per real */
 492         MAX_HD,         /* maximum number of real */
 493         hd_geninit,     /* init function */
 494         hd,             /* hd struct */
 495         hd_sizes,       /* block sizes */
 496         0,              /* number */
 497         (void *) hd_info,       /* internal */
 498         NULL            /* next */
 499 };
 500         
 501 static void hd_geninit(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 502 {
 503         int drive;
 504 #ifndef HD_TYPE
 505         extern struct drive_info drive_info;
 506         void *BIOS = (void *) &drive_info;
 507         int cmos_disks, i;
 508            
 509         for (drive=0 ; drive<2 ; drive++) {
 510                 hd_info[drive].cyl = *(unsigned short *) BIOS;
 511                 hd_info[drive].head = *(unsigned char *) (2+BIOS);
 512                 hd_info[drive].wpcom = *(unsigned short *) (5+BIOS);
 513                 hd_info[drive].ctl = *(unsigned char *) (8+BIOS);
 514                 hd_info[drive].lzone = *(unsigned short *) (12+BIOS);
 515                 hd_info[drive].sect = *(unsigned char *) (14+BIOS);
 516                 BIOS += 16;
 517         }
 518 
 519         /*
 520                 We querry CMOS about hard disks : it could be that 
 521                 we have a SCSI/ESDI/etc controller that is BIOS
 522                 compatable with ST-506, and thus showing up in our
 523                 BIOS table, but not register compatable, and therefore
 524                 not present in CMOS.
 525 
 526                 Furthurmore, we will assume that our ST-506 drives
 527                 <if any> are the primary drives in the system, and 
 528                 the ones reflected as drive 1 or 2.
 529 
 530                 The first drive is stored in the high nibble of CMOS
 531                 byte 0x12, the second in the low nibble.  This will be
 532                 either a 4 bit drive type or 0xf indicating use byte 0x19 
 533                 for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS.
 534 
 535                 Needless to say, a non-zero value means we have 
 536                 an AT controller hard disk for that drive.
 537 
 538                 
 539         */
 540 
 541         if ((cmos_disks = CMOS_READ(0x12)) & 0xf0)
 542                 if (cmos_disks & 0x0f)
 543                         NR_HD = 2;
 544                 else
 545                         NR_HD = 1;
 546         else
 547                 NR_HD = 0;
 548 #endif
 549 
 550         for (i = 0 ; i < NR_HD ; i++)
 551                 hd[i<<6].nr_sects = hd_info[i].head*
 552                                 hd_info[i].sect*hd_info[i].cyl;
 553 
 554         hd_gendisk.nr_real = NR_HD;
 555 }
 556 
 557 static struct file_operations hd_fops = {
 558         NULL,                   /* lseek - default */
 559         block_read,             /* read - general block-dev read */
 560         block_write,            /* write - general block-dev write */
 561         NULL,                   /* readdir - bad */
 562         NULL,                   /* select */
 563         hd_ioctl,               /* ioctl */
 564         NULL,                   /* no special open code */
 565         hd_release              /* release */
 566 };
 567 
 568 static void hd_interrupt(int unused)
     /* [previous][next][first][last][top][bottom][index][help] */
 569 {
 570         void (*handler)(void) = DEVICE_INTR;
 571 
 572         DEVICE_INTR = NULL;
 573         timer_active &= ~(1<<HD_TIMER);
 574         if (!handler)
 575                 handler = unexpected_hd_interrupt;
 576         handler();
 577         sti();
 578 }
 579 
 580 /*
 581  * This is the harddisk IRQ descruption. The SA_INTERRUPT in sa_flags
 582  * means we run the IRQ-handler with interrupts disabled: this is bad for
 583  * interrupt latency, but anything else has led to problems on some
 584  * machines...
 585  *
 586  * We enable interrupts in some of the routines after making sure it's
 587  * safe.
 588  */
 589 static struct sigaction hd_sigaction = {
 590         hd_interrupt,
 591         0,
 592         SA_INTERRUPT,
 593         NULL
 594 };
 595 
 596 void hd_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 597 {
 598         blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
 599         blkdev_fops[MAJOR_NR] = &hd_fops;
 600         hd_gendisk.next = gendisk_head;
 601         gendisk_head = &hd_gendisk;
 602         if (irqaction(HD_IRQ,&hd_sigaction))
 603                 printk("Unable to get IRQ%d for the harddisk driver\n",HD_IRQ);
 604         timer_table[HD_TIMER].fn = hd_times_out;
 605 }
 606 
 607 #endif

/* [previous][next][first][last][top][bottom][index][help] */