root/drivers/block/hd.c

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

DEFINITIONS

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

   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 
  20 #include <linux/errno.h>
  21 #include <linux/signal.h>
  22 #include <linux/sched.h>
  23 #include <linux/timer.h>
  24 #include <linux/fs.h>
  25 #include <linux/kernel.h>
  26 #include <linux/hdreg.h>
  27 #include <linux/genhd.h>
  28 #include <linux/config.h>
  29 
  30 #define REALLY_SLOW_IO
  31 #include <asm/system.h>
  32 #include <asm/io.h>
  33 #include <asm/segment.h>
  34 
  35 #define MAJOR_NR HD_MAJOR
  36 #include "blk.h"
  37 
  38 #define HD_IRQ 14
  39 
  40 static int revalidate_hddisk(int, int);
  41 
  42 static inline unsigned char CMOS_READ(unsigned char addr)
     /* [previous][next][first][last][top][bottom][index][help] */
  43 {
  44         outb_p(addr,0x70);
  45         return inb_p(0x71);
  46 }
  47 
  48 #define HD_DELAY        0
  49 
  50 #define MAX_ERRORS     16       /* Max read/write errors/sector */
  51 #define RESET_FREQ      8       /* Reset controller every 8th retry */
  52 #define RECAL_FREQ      4       /* Recalibrate every 4th retry */
  53 #define MAX_HD          2
  54 
  55 static void recal_intr(void);
  56 static void bad_rw_intr(void);
  57 
  58 static char recalibrate[ MAX_HD ] = { 0, };
  59 static int access_count[MAX_HD] = {0, };
  60 static char busy[MAX_HD] = {0, };
  61 static struct wait_queue * busy_wait = NULL;
  62 
  63 static int reset = 0;
  64 static int hd_error = 0;
  65 
  66 #if (HD_DELAY > 0)
  67 unsigned long last_req, read_timer();
  68 #endif
  69 
  70 /*
  71  *  This struct defines the HD's and their types.
  72  */
  73 struct hd_i_struct {
  74         unsigned int head,sect,cyl,wpcom,lzone,ctl;
  75         };
  76 #ifdef HD_TYPE
  77 struct hd_i_struct hd_info[] = { HD_TYPE };
  78 static int NR_HD = ((sizeof (hd_info))/(sizeof (struct hd_i_struct)));
  79 #else
  80 struct hd_i_struct hd_info[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} };
  81 static int NR_HD = 0;
  82 #endif
  83 
  84 static struct hd_struct hd[MAX_HD<<6]={{0,0},};
  85 static int hd_sizes[MAX_HD<<6] = {0, };
  86 static int hd_blocksizes[MAX_HD<<6] = {0, };
  87 
  88 #if (HD_DELAY > 0)
  89 unsigned long read_timer(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  90 {
  91         unsigned long t;
  92         int i;
  93 
  94         cli();
  95         t = jiffies * 11932;
  96         outb_p(0, 0x43);
  97         i = inb_p(0x40);
  98         i |= inb(0x40) << 8;
  99         sti();
 100         return(t - i);
 101 }
 102 #endif
 103 
 104 void hd_setup(char *str, int *ints)
     /* [previous][next][first][last][top][bottom][index][help] */
 105 {
 106         int hdind = 0;
 107 
 108         if (ints[0] != 3)
 109                 return;
 110         if (hd_info[0].head != 0)
 111                 hdind=1;
 112         hd_info[hdind].head = ints[2];
 113         hd_info[hdind].sect = ints[3];
 114         hd_info[hdind].cyl = ints[1];
 115         hd_info[hdind].wpcom = 0;
 116         hd_info[hdind].lzone = ints[1];
 117         hd_info[hdind].ctl = (ints[2] > 8 ? 8 : 0);
 118         NR_HD = hdind+1;
 119 }
 120 
 121 static int win_result(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 122 {
 123         int i=inb_p(HD_STATUS);
 124 
 125         if ((i & (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT))
 126                 == (READY_STAT | SEEK_STAT)) {
 127                 hd_error = 0;
 128                 return 0; /* ok */
 129         }
 130         printk("HD: win_result: status = 0x%02x\n",i);
 131         if (i&1) {
 132                 hd_error = inb(HD_ERROR);
 133                 printk("HD: win_result: error = 0x%02x\n",hd_error);
 134         }       
 135         return 1;
 136 }
 137 
 138 static int controller_busy(void);
 139 static int status_ok(void);
 140 
 141 static int controller_ready(unsigned int drive, unsigned int head)
     /* [previous][next][first][last][top][bottom][index][help] */
 142 {
 143         int retry = 100;
 144 
 145         do {
 146                 if (controller_busy() & BUSY_STAT)
 147                         return 0;
 148                 outb_p(0xA0 | (drive<<4) | head, HD_CURRENT);
 149                 if (status_ok())
 150                         return 1;
 151         } while (--retry);
 152         return 0;
 153 }
 154 
 155 static int status_ok(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 156 {
 157         unsigned char status = inb_p(HD_STATUS);
 158 
 159         if (status & BUSY_STAT)
 160                 return 1;
 161         if (status & WRERR_STAT)
 162                 return 0;
 163         if (!(status & READY_STAT))
 164                 return 0;
 165         if (!(status & SEEK_STAT))
 166                 return 0;
 167         return 1;
 168 }
 169 
 170 static int controller_busy(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 171 {
 172         int retries = 100000;
 173         unsigned char status;
 174 
 175         do {
 176                 status = inb_p(HD_STATUS);
 177         } while ((status & BUSY_STAT) && --retries);
 178         return status;
 179 }
 180 
 181 static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
     /* [previous][next][first][last][top][bottom][index][help] */
 182                 unsigned int head,unsigned int cyl,unsigned int cmd,
 183                 void (*intr_addr)(void))
 184 {
 185         unsigned short port;
 186 
 187         if (drive>1 || head>15) {
 188                 printk("bad drive mapping, trying to access drive=%d, cyl=%d, head=%d, sect=%d\n",
 189                         drive, cyl, head, sect);
 190                 panic("harddisk driver problem");
 191         }
 192 #if (HD_DELAY > 0)
 193         while (read_timer() - last_req < HD_DELAY)
 194                 /* nothing */;
 195 #endif
 196         if (reset)
 197                 return;
 198         if (!controller_ready(drive, head)) {
 199                 reset = 1;
 200                 return;
 201         }
 202         SET_INTR(intr_addr);
 203         outb_p(hd_info[drive].ctl,HD_CMD);
 204         port=HD_DATA;
 205         outb_p(hd_info[drive].wpcom>>2,++port);
 206         outb_p(nsect,++port);
 207         outb_p(sect,++port);
 208         outb_p(cyl,++port);
 209         outb_p(cyl>>8,++port);
 210         outb_p(0xA0|(drive<<4)|head,++port);
 211         outb_p(cmd,++port);
 212 }
 213 
 214 static int drive_busy(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 215 {
 216         unsigned int i;
 217         unsigned char c;
 218 
 219         for (i = 0; i < 500000 ; i++) {
 220                 c = inb_p(HD_STATUS);
 221                 c &= (BUSY_STAT | READY_STAT | SEEK_STAT);
 222                 if (c == (READY_STAT | SEEK_STAT))
 223                         return 0;
 224         }
 225         printk("HD controller times out, status = 0x%02x\n",c);
 226         return 1;
 227 }
 228 
 229 static void reset_controller(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 230 {
 231         int     i;
 232 
 233         printk(KERN_DEBUG "HD-controller reset\n");
 234         outb_p(4,HD_CMD);
 235         for(i = 0; i < 1000; i++) nop();
 236         outb(hd_info[0].ctl & 0x0f ,HD_CMD);
 237         if (drive_busy())
 238                 printk("HD-controller still busy\n");
 239         if ((hd_error = inb(HD_ERROR)) != 1)
 240                 printk("HD-controller reset failed: %02x\n",hd_error);
 241 }
 242 
 243 static void reset_hd(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 244 {
 245         static int i;
 246 
 247 repeat:
 248         if (reset) {
 249                 reset = 0;
 250                 i = -1;
 251                 reset_controller();
 252         } else if (win_result()) {
 253                 bad_rw_intr();
 254                 if (reset)
 255                         goto repeat;
 256         }
 257         i++;
 258         if (i < NR_HD) {
 259                 hd_out(i,hd_info[i].sect,hd_info[i].sect,hd_info[i].head-1,
 260                         hd_info[i].cyl,WIN_SPECIFY,&reset_hd);
 261                 if (reset)
 262                         goto repeat;
 263         } else
 264                 do_hd_request();
 265 }
 266 
 267 /*
 268  * Ok, don't know what to do with the unexpected interrupts: on some machines
 269  * doing a reset and a retry seems to result in an eternal loop. Right now I
 270  * ignore it, and just set the timeout.
 271  */
 272 void unexpected_hd_interrupt(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 273 {
 274         sti();
 275         printk(KERN_DEBUG "Unexpected HD interrupt\n");
 276         SET_TIMER;
 277 }
 278 
 279 /*
 280  * bad_rw_intr() now tries to be a bit smarter and does things
 281  * according to the error returned by the controller.
 282  * -Mika Liljeberg (liljeber@cs.Helsinki.FI)
 283  */
 284 static void bad_rw_intr(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 285 {
 286         int dev;
 287 
 288         if (!CURRENT)
 289                 return;
 290         dev = MINOR(CURRENT->dev) >> 6;
 291         if (++CURRENT->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) {
 292                 end_request(0);
 293                 recalibrate[dev] = 1;
 294         } else if (CURRENT->errors % RESET_FREQ == 0)
 295                 reset = 1;
 296         else if ((hd_error & TRK0_ERR) || CURRENT->errors % RECAL_FREQ == 0)
 297                 recalibrate[dev] = 1;
 298         /* Otherwise just retry */
 299 }
 300 
 301 static inline int wait_DRQ(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 302 {
 303         int retries = 100000;
 304 
 305         while (--retries > 0)
 306                 if (inb_p(HD_STATUS) & DRQ_STAT)
 307                         return 0;
 308         return -1;
 309 }
 310 
 311 #define STAT_MASK (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT)
 312 #define STAT_OK (READY_STAT | SEEK_STAT)
 313 
 314 static void read_intr(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 315 {
 316         int i;
 317         int retries = 100000;
 318 
 319         do {
 320                 i = (unsigned) inb_p(HD_STATUS);
 321                 if (i & BUSY_STAT)
 322                         continue;
 323                 if ((i & STAT_MASK) != STAT_OK)
 324                         break;
 325                 if (i & DRQ_STAT)
 326                         goto ok_to_read;
 327         } while (--retries > 0);
 328         sti();
 329         printk("HD: read_intr: status = 0x%02x\n",i);
 330         if (i & ERR_STAT) {
 331                 hd_error = (unsigned) inb(HD_ERROR);
 332                 printk("HD: read_intr: error = 0x%02x\n",hd_error);
 333         }
 334         bad_rw_intr();
 335         cli();
 336         do_hd_request();
 337         return;
 338 ok_to_read:
 339         insw(HD_DATA,CURRENT->buffer,256);
 340         CURRENT->errors = 0;
 341         CURRENT->buffer += 512;
 342         CURRENT->sector++;
 343         i = --CURRENT->nr_sectors;
 344         --CURRENT->current_nr_sectors;
 345 #ifdef DEBUG
 346         printk("hd%d : sector = %d, %d remaining to buffer = %08x\n",
 347                 MINOR(CURRENT->dev), CURRENT->sector, i, CURRENT-> 
 348                 buffer);
 349 #endif
 350         if (!i || (CURRENT->bh && !SUBSECTOR(i)))
 351                 end_request(1);
 352         if (i > 0) {
 353                 SET_INTR(&read_intr);
 354                 sti();
 355                 return;
 356         }
 357         (void) inb_p(HD_STATUS);
 358 #if (HD_DELAY > 0)
 359         last_req = read_timer();
 360 #endif
 361         do_hd_request();
 362         return;
 363 }
 364 
 365 static void write_intr(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 366 {
 367         int i;
 368         int retries = 100000;
 369 
 370         do {
 371                 i = (unsigned) inb_p(HD_STATUS);
 372                 if (i & BUSY_STAT)
 373                         continue;
 374                 if ((i & STAT_MASK) != STAT_OK)
 375                         break;
 376                 if ((CURRENT->nr_sectors <= 1) || (i & DRQ_STAT))
 377                         goto ok_to_write;
 378         } while (--retries > 0);
 379         sti();
 380         printk("HD: write_intr: status = 0x%02x\n",i);
 381         if (i & ERR_STAT) {
 382                 hd_error = (unsigned) inb(HD_ERROR);
 383                 printk("HD: write_intr: error = 0x%02x\n",hd_error);
 384         }
 385         bad_rw_intr();
 386         cli();
 387         do_hd_request();
 388         return;
 389 ok_to_write:
 390         CURRENT->sector++;
 391         i = --CURRENT->nr_sectors;
 392         --CURRENT->current_nr_sectors;
 393         CURRENT->buffer += 512;
 394         if (!i || (CURRENT->bh && !SUBSECTOR(i)))
 395                 end_request(1);
 396         if (i > 0) {
 397                 SET_INTR(&write_intr);
 398                 outsw(HD_DATA,CURRENT->buffer,256);
 399                 sti();
 400         } else {
 401 #if (HD_DELAY > 0)
 402                 last_req = read_timer();
 403 #endif
 404                 do_hd_request();
 405         }
 406         return;
 407 }
 408 
 409 static void recal_intr(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 410 {
 411         if (win_result())
 412                 bad_rw_intr();
 413         do_hd_request();
 414 }
 415 
 416 /*
 417  * This is another of the error-routines I don't know what to do with. The
 418  * best idea seems to just set reset, and start all over again.
 419  */
 420 static void hd_times_out(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 421 {
 422         DEVICE_INTR = NULL;
 423         sti();
 424         reset = 1;
 425         if (!CURRENT)
 426                 return;
 427         printk(KERN_DEBUG "HD timeout\n");
 428         cli();
 429         if (++CURRENT->errors >= MAX_ERRORS) {
 430 #ifdef DEBUG
 431                 printk("hd : too many errors.\n");
 432 #endif
 433                 end_request(0);
 434         }
 435 
 436         do_hd_request();
 437 }
 438 
 439 /*
 440  * The driver has been modified to enable interrupts a bit more: in order to
 441  * do this we first (a) disable the timeout-interrupt and (b) clear the
 442  * device-interrupt. This way the interrupts won't mess with out code (the
 443  * worst that can happen is that an unexpected HD-interrupt comes in and
 444  * sets the "reset" variable and starts the timer)
 445  */
 446 static void do_hd_request(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 447 {
 448         unsigned int block,dev;
 449         unsigned int sec,head,cyl,track;
 450         unsigned int nsect;
 451 
 452         if (CURRENT && CURRENT->dev < 0) return;
 453 
 454         if (DEVICE_INTR)
 455                 return;
 456 repeat:
 457         timer_active &= ~(1<<HD_TIMER);
 458         sti();
 459         INIT_REQUEST;
 460         dev = MINOR(CURRENT->dev);
 461         block = CURRENT->sector;
 462         nsect = CURRENT->nr_sectors;
 463         if (dev >= (NR_HD<<6) || block >= hd[dev].nr_sects) {
 464 #ifdef DEBUG
 465                 printk("hd%d : attempted read for sector %d past end of device at sector %d.\n",
 466                         block, hd[dev].nr_sects);
 467 #endif
 468                 end_request(0);
 469                 goto repeat;
 470         }
 471         block += hd[dev].start_sect;
 472         dev >>= 6;
 473         sec = block % hd_info[dev].sect + 1;
 474         track = block / hd_info[dev].sect;
 475         head = track % hd_info[dev].head;
 476         cyl = track / hd_info[dev].head;
 477 #ifdef DEBUG
 478         printk("hd%d : cyl = %d, head = %d, sector = %d, buffer = %08x\n",
 479                 dev, cyl, head, sec, CURRENT->buffer);
 480 #endif
 481         cli();
 482         if (reset) {
 483                 int i;
 484 
 485                 for (i=0; i < NR_HD; i++)
 486                         recalibrate[i] = 1;
 487                 reset_hd();
 488                 sti();
 489                 return;
 490         }
 491         if (recalibrate[dev]) {
 492                 recalibrate[dev] = 0;
 493                 hd_out(dev,hd_info[dev].sect,0,0,0,WIN_RESTORE,&recal_intr);
 494                 if (reset)
 495                         goto repeat;
 496                 sti();
 497                 return;
 498         }       
 499         if (CURRENT->cmd == WRITE) {
 500                 hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
 501                 if (reset)
 502                         goto repeat;
 503                 if (wait_DRQ()) {
 504                         printk("HD: do_hd_request: no DRQ\n");
 505                         bad_rw_intr();
 506                         goto repeat;
 507                 }
 508                 outsw(HD_DATA,CURRENT->buffer,256);
 509                 sti();
 510                 return;
 511         }
 512         if (CURRENT->cmd == READ) {
 513                 hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr);
 514                 if (reset)
 515                         goto repeat;
 516                 sti();
 517                 return;
 518         }
 519         panic("unknown hd-command");
 520 }
 521 
 522 static int hd_ioctl(struct inode * inode, struct file * file,
     /* [previous][next][first][last][top][bottom][index][help] */
 523         unsigned int cmd, unsigned long arg)
 524 {
 525         struct hd_geometry *loc = (struct hd_geometry *) arg;
 526         int dev, err;
 527 
 528         if (!inode)
 529                 return -EINVAL;
 530         dev = MINOR(inode->i_rdev) >> 6;
 531         if (dev >= NR_HD)
 532                 return -EINVAL;
 533         switch (cmd) {
 534                 case HDIO_GETGEO:
 535                         if (!loc)  return -EINVAL;
 536                         err = verify_area(VERIFY_WRITE, loc, sizeof(*loc));
 537                         if (err)
 538                                 return err;
 539                         put_fs_byte(hd_info[dev].head,
 540                                 (char *) &loc->heads);
 541                         put_fs_byte(hd_info[dev].sect,
 542                                 (char *) &loc->sectors);
 543                         put_fs_word(hd_info[dev].cyl,
 544                                 (short *) &loc->cylinders);
 545                         put_fs_long(hd[MINOR(inode->i_rdev)].start_sect,
 546                                 (long *) &loc->start);
 547                         return 0;
 548                 case BLKRASET:
 549                         if(!suser())  return -EACCES;
 550                         if(!inode->i_rdev) return -EINVAL;
 551                         if(arg > 0xff) return -EINVAL;
 552                         read_ahead[MAJOR(inode->i_rdev)] = arg;
 553                         return 0;
 554                 case BLKGETSIZE:   /* Return device size */
 555                         if (!arg)  return -EINVAL;
 556                         err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
 557                         if (err)
 558                                 return err;
 559                         put_fs_long(hd[MINOR(inode->i_rdev)].nr_sects,
 560                                 (long *) arg);
 561                         return 0;
 562                 case BLKFLSBUF:
 563                         if(!suser())  return -EACCES;
 564                         if(!inode->i_rdev) return -EINVAL;
 565                         fsync_dev(inode->i_rdev);
 566                         invalidate_buffers(inode->i_rdev);
 567                         return 0;
 568 
 569                 case BLKRRPART: /* Re-read partition tables */
 570                         return revalidate_hddisk(inode->i_rdev, 1);
 571                 RO_IOCTLS(inode->i_rdev,arg);
 572                 default:
 573                         return -EINVAL;
 574         }
 575 }
 576 
 577 static int hd_open(struct inode * inode, struct file * filp)
     /* [previous][next][first][last][top][bottom][index][help] */
 578 {
 579         int target;
 580         target =  DEVICE_NR(MINOR(inode->i_rdev));
 581 
 582         while (busy[target])
 583                 sleep_on(&busy_wait);
 584         access_count[target]++;
 585         return 0;
 586 }
 587 
 588 /*
 589  * Releasing a block device means we sync() it, so that it can safely
 590  * be forgotten about...
 591  */
 592 static void hd_release(struct inode * inode, struct file * file)
     /* [previous][next][first][last][top][bottom][index][help] */
 593 {
 594         int target;
 595         sync_dev(inode->i_rdev);
 596 
 597         target =  DEVICE_NR(MINOR(inode->i_rdev));
 598         access_count[target]--;
 599 
 600 }
 601 
 602 static void hd_geninit(void);
 603 
 604 static struct gendisk hd_gendisk = {
 605         MAJOR_NR,       /* Major number */      
 606         "hd",           /* Major name */
 607         6,              /* Bits to shift to get real from partition */
 608         1 << 6,         /* Number of partitions per real */
 609         MAX_HD,         /* maximum number of real */
 610         hd_geninit,     /* init function */
 611         hd,             /* hd struct */
 612         hd_sizes,       /* block sizes */
 613         0,              /* number */
 614         (void *) hd_info,       /* internal */
 615         NULL            /* next */
 616 };
 617         
 618 static void hd_interrupt(int unused)
     /* [previous][next][first][last][top][bottom][index][help] */
 619 {
 620         void (*handler)(void) = DEVICE_INTR;
 621 
 622         DEVICE_INTR = NULL;
 623         timer_active &= ~(1<<HD_TIMER);
 624         if (!handler)
 625                 handler = unexpected_hd_interrupt;
 626         handler();
 627         sti();
 628 }
 629 
 630 /*
 631  * This is the harddisk IRQ description. The SA_INTERRUPT in sa_flags
 632  * means we run the IRQ-handler with interrupts disabled: this is bad for
 633  * interrupt latency, but anything else has led to problems on some
 634  * machines...
 635  *
 636  * We enable interrupts in some of the routines after making sure it's
 637  * safe.
 638  */
 639 static struct sigaction hd_sigaction = {
 640         hd_interrupt,
 641         0,
 642         SA_INTERRUPT,
 643         NULL
 644 };
 645 
 646 static void hd_geninit(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 647 {
 648         int drive, i;
 649         extern struct drive_info drive_info;
 650         unsigned char *BIOS = (unsigned char *) &drive_info;
 651         int cmos_disks;
 652 
 653         if (!NR_HD) {      
 654                 for (drive=0 ; drive<2 ; drive++) {
 655                         hd_info[drive].cyl = *(unsigned short *) BIOS;
 656                         hd_info[drive].head = *(2+BIOS);
 657                         hd_info[drive].wpcom = *(unsigned short *) (5+BIOS);
 658                         hd_info[drive].ctl = *(8+BIOS);
 659                         hd_info[drive].lzone = *(unsigned short *) (12+BIOS);
 660                         hd_info[drive].sect = *(14+BIOS);
 661 #ifdef does_not_work_for_everybody_with_scsi_but_helps_ibm_vp
 662                         if (hd_info[drive].cyl && NR_HD == drive)
 663                                 NR_HD++;
 664 #endif
 665                         BIOS += 16;
 666                 }
 667 
 668         /*
 669                 We querry CMOS about hard disks : it could be that 
 670                 we have a SCSI/ESDI/etc controller that is BIOS
 671                 compatable with ST-506, and thus showing up in our
 672                 BIOS table, but not register compatable, and therefore
 673                 not present in CMOS.
 674 
 675                 Furthurmore, we will assume that our ST-506 drives
 676                 <if any> are the primary drives in the system, and 
 677                 the ones reflected as drive 1 or 2.
 678 
 679                 The first drive is stored in the high nibble of CMOS
 680                 byte 0x12, the second in the low nibble.  This will be
 681                 either a 4 bit drive type or 0xf indicating use byte 0x19 
 682                 for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS.
 683 
 684                 Needless to say, a non-zero value means we have 
 685                 an AT controller hard disk for that drive.
 686 
 687                 
 688         */
 689 
 690                 if ((cmos_disks = CMOS_READ(0x12)) & 0xf0)
 691                         if (cmos_disks & 0x0f)
 692                                 NR_HD = 2;
 693                         else
 694                                 NR_HD = 1;
 695         }
 696         i = NR_HD;
 697         while (i-- > 0) {
 698                 hd[i<<6].nr_sects = 0;
 699                 if (hd_info[i].head > 16) {
 700                         printk("hd.c: ST-506 interface disk with more than 16 heads detected,\n");
 701                         printk("  probably due to non-standard sector translation. Giving up.\n");
 702                         printk("  (disk %d: cyl=%d, sect=%d, head=%d)\n", i,
 703                                 hd_info[i].cyl,
 704                                 hd_info[i].sect,
 705                                 hd_info[i].head);
 706                         if (i+1 == NR_HD)
 707                                 NR_HD--;
 708                         continue;
 709                 }
 710                 hd[i<<6].nr_sects = hd_info[i].head*
 711                                 hd_info[i].sect*hd_info[i].cyl;
 712         }
 713         if (NR_HD) {
 714                 if (irqaction(HD_IRQ,&hd_sigaction)) {
 715                         printk("hd.c: unable to get IRQ%d for the harddisk driver\n",HD_IRQ);
 716                         NR_HD = 0;
 717                 }
 718         }
 719         hd_gendisk.nr_real = NR_HD;
 720 
 721         for(i=0;i<(MAX_HD << 6);i++) hd_blocksizes[i] = 1024;
 722         blksize_size[MAJOR_NR] = hd_blocksizes;
 723 }
 724 
 725 static struct file_operations hd_fops = {
 726         NULL,                   /* lseek - default */
 727         block_read,             /* read - general block-dev read */
 728         block_write,            /* write - general block-dev write */
 729         NULL,                   /* readdir - bad */
 730         NULL,                   /* select */
 731         hd_ioctl,               /* ioctl */
 732         NULL,                   /* mmap */
 733         hd_open,                /* open */
 734         hd_release,             /* release */
 735         block_fsync             /* fsync */
 736 };
 737 
 738 unsigned long hd_init(unsigned long mem_start, unsigned long mem_end)
     /* [previous][next][first][last][top][bottom][index][help] */
 739 {
 740         if (register_blkdev(MAJOR_NR,"hd",&hd_fops)) {
 741                 printk("Unable to get major %d for harddisk\n",MAJOR_NR);
 742                 return mem_start;
 743         }
 744         blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
 745         read_ahead[MAJOR_NR] = 8;               /* 8 sector (4kB) read-ahead */
 746         hd_gendisk.next = gendisk_head;
 747         gendisk_head = &hd_gendisk;
 748         timer_table[HD_TIMER].fn = hd_times_out;
 749         return mem_start;
 750 }
 751 
 752 #define DEVICE_BUSY busy[target]
 753 #define USAGE access_count[target]
 754 #define CAPACITY (hd_info[target].head*hd_info[target].sect*hd_info[target].cyl)
 755 /* We assume that the the bios parameters do not change, so the disk capacity
 756    will not change */
 757 #undef MAYBE_REINIT
 758 #define GENDISK_STRUCT hd_gendisk
 759 
 760 /*
 761  * This routine is called to flush all partitions and partition tables
 762  * for a changed scsi disk, and then re-read the new partition table.
 763  * If we are revalidating a disk because of a media change, then we
 764  * enter with usage == 0.  If we are using an ioctl, we automatically have
 765  * usage == 1 (we need an open channel to use an ioctl :-), so this
 766  * is our limit.
 767  */
 768 static int revalidate_hddisk(int dev, int maxusage)
     /* [previous][next][first][last][top][bottom][index][help] */
 769 {
 770         int target, major;
 771         struct gendisk * gdev;
 772         int max_p;
 773         int start;
 774         int i;
 775 
 776         target =  DEVICE_NR(MINOR(dev));
 777         gdev = &GENDISK_STRUCT;
 778 
 779         cli();
 780         if (DEVICE_BUSY || USAGE > maxusage) {
 781                 sti();
 782                 return -EBUSY;
 783         };
 784         DEVICE_BUSY = 1;
 785         sti();
 786 
 787         max_p = gdev->max_p;
 788         start = target << gdev->minor_shift;
 789         major = MAJOR_NR << 8;
 790 
 791         for (i=max_p - 1; i >=0 ; i--) {
 792                 sync_dev(major | start | i);
 793                 invalidate_inodes(major | start | i);
 794                 invalidate_buffers(major | start | i);
 795                 gdev->part[start+i].start_sect = 0;
 796                 gdev->part[start+i].nr_sects = 0;
 797         };
 798 
 799 #ifdef MAYBE_REINIT
 800         MAYBE_REINIT;
 801 #endif
 802 
 803         gdev->part[start].nr_sects = CAPACITY;
 804         resetup_one_dev(gdev, target);
 805 
 806         DEVICE_BUSY = 0;
 807         wake_up(&busy_wait);
 808         return 0;
 809 }
 810 

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