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. extended_partition
  3. check_partition
  4. sys_setup
  5. controller_ready
  6. win_result
  7. hd_out
  8. drive_busy
  9. reset_controller
  10. reset_hd
  11. unexpected_hd_interrupt
  12. bad_rw_intr
  13. read_intr
  14. write_intr
  15. recal_intr
  16. hd_times_out
  17. do_hd_request
  18. hd_init
  19. hd_ioctl

   1 /*
   2  *  linux/kernel/hd.c
   3  *
   4  *  (C) 1991  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 <errno.h>
  20 
  21 #include <linux/config.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 <asm/system.h>
  28 #include <asm/io.h>
  29 #include <asm/segment.h>
  30 
  31 #define MAJOR_NR 3
  32 #include "blk.h"
  33 
  34 static inline unsigned char CMOS_READ(unsigned char addr)
     /* [previous][next][first][last][top][bottom][index][help] */
  35 {
  36         outb_p(0x80|addr,0x70);
  37         return inb_p(0x71);
  38 }
  39 
  40 /* Max read/write errors/sector */
  41 #define MAX_ERRORS      7
  42 #define MAX_HD          2
  43 
  44 static void recal_intr(void);
  45 static void bad_rw_intr(void);
  46 
  47 static int recalibrate = 0;
  48 static int reset = 0;
  49 
  50 /*
  51  *  This struct defines the HD's and their types.
  52  */
  53 struct hd_i_struct {
  54         unsigned int head,sect,cyl,wpcom,lzone,ctl;
  55         };
  56 #ifdef HD_TYPE
  57 struct hd_i_struct hd_info[] = { HD_TYPE };
  58 #define NR_HD ((sizeof (hd_info))/(sizeof (struct hd_i_struct)))
  59 #else
  60 struct hd_i_struct hd_info[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} };
  61 static int NR_HD = 0;
  62 #endif
  63 
  64 static struct hd_struct {
  65         long start_sect;
  66         long nr_sects;
  67 } hd[MAX_HD<<6]={{0,0},};
  68 
  69 static int hd_sizes[MAX_HD<<6] = {0, };
  70 
  71 #define port_read(port,buf,nr) \
  72 __asm__("cld;rep;insw"::"d" (port),"D" (buf),"c" (nr):"cx","di")
  73 
  74 #define port_write(port,buf,nr) \
  75 __asm__("cld;rep;outsw"::"d" (port),"S" (buf),"c" (nr):"cx","si")
  76 
  77 extern void hd_interrupt(void);
  78 extern void rd_load(void);
  79 
  80 static unsigned int current_minor;
  81 
  82 /*
  83  * Create devices for each logical partition in an extended partition.
  84  * The logical partitions form a linked list, with each entry being
  85  * a partition table with two entries.  The first entry
  86  * is the real data partition (with a start relative to the partition
  87  * table start).  The second is a pointer to the next logical partition
  88  * (with a start relative to the entire extended partition).
  89  * We do not create a Linux partition for the partition tables, but
  90  * only for the actual data partitions.
  91  */
  92 static void extended_partition(unsigned int dev)
     /* [previous][next][first][last][top][bottom][index][help] */
  93 {
  94         struct buffer_head *bh;
  95         struct partition *p;
  96         unsigned long first_sector, this_sector;
  97 
  98         first_sector = hd[MINOR(dev)].start_sect;
  99         this_sector = first_sector;
 100 
 101         while (1) {
 102                 if ((current_minor & 0x3f) >= 60)
 103                         return;
 104                 if (!(bh = bread(dev,0))) {
 105                         printk("Unable to read partition table of device %04x\n",dev);
 106                         return;
 107                 }
 108           /*
 109            * This block is from a device that we're about to stomp on.
 110            * So make sure nobody thinks this block is usable.
 111            */
 112                 bh->b_dirt=0;
 113                 bh->b_uptodate=0;
 114                 if (*(unsigned short *) (bh->b_data+510) == 0xAA55) {
 115                         p = 0x1BE + (void *)bh->b_data;
 116                 /*
 117                  * Process the first entry, which should be the real
 118                  * data partition.
 119                  */
 120                         if (p->sys_ind == EXTENDED_PARTITION ||
 121                             !(hd[current_minor].nr_sects = p->nr_sects))
 122                                 goto done;  /* shouldn't happen */
 123                         hd[current_minor].start_sect = this_sector + p->start_sect;
 124                         printk("  Logical part %d start %d size %d end %d\n\r", 
 125                                current_minor, hd[current_minor].start_sect, 
 126                                hd[current_minor].nr_sects,
 127                                hd[current_minor].start_sect + 
 128                                hd[current_minor].nr_sects);
 129                         current_minor++;
 130                         p++;
 131                 /*
 132                  * Process the second entry, which should be a link
 133                  * to the next logical partition.  Create a minor
 134                  * for this just long enough to get the next partition
 135                  * table.  The minor will be reused for the real
 136                  * data partition.
 137                  */
 138                         if (p->sys_ind != EXTENDED_PARTITION ||
 139                             !(hd[current_minor].nr_sects = p->nr_sects))
 140                                 goto done;  /* no more logicals in this partition */
 141                         hd[current_minor].start_sect = first_sector + p->start_sect;
 142                         this_sector = first_sector + p->start_sect;
 143                         dev = 0x0300 | current_minor;
 144                         brelse(bh);
 145                 } else
 146                         goto done;
 147         }
 148 done:
 149         brelse(bh);
 150 }
 151 
 152 static void check_partition(unsigned int dev)
     /* [previous][next][first][last][top][bottom][index][help] */
 153 {
 154         int i, minor = current_minor;
 155         struct buffer_head *bh;
 156         struct partition *p;
 157         unsigned long first_sector;
 158 
 159         first_sector = hd[MINOR(dev)].start_sect;
 160         if (!(bh = bread(dev,0))) {
 161                 printk("Unable to read partition table of device %04x\n",dev);
 162                 return;
 163         }
 164         printk("Drive %d:\n\r",minor >> 6);
 165         current_minor += 4;  /* first "extra" minor */
 166         if (*(unsigned short *) (bh->b_data+510) == 0xAA55) {
 167                 p = 0x1BE + (void *)bh->b_data;
 168                 for (i=1 ; i<=4 ; minor++,i++,p++) {
 169                         if (!(hd[minor].nr_sects = p->nr_sects))
 170                                 continue;
 171                         hd[minor].start_sect = first_sector + p->start_sect;
 172                         printk(" part %d start %d size %d end %d \n\r", i, 
 173                                hd[minor].start_sect, hd[minor].nr_sects, 
 174                                hd[minor].start_sect + hd[minor].nr_sects);
 175                         if ((current_minor & 0x3f) >= 60)
 176                                 continue;
 177                         if (p->sys_ind == EXTENDED_PARTITION) {
 178                                 extended_partition(0x0300 | minor);
 179                         }
 180                 }
 181                 /*
 182                  * check for Disk Manager partition table
 183                  */
 184                 if (*(unsigned short *) (bh->b_data+0xfc) == 0x55AA) {
 185                         p = 0x1BE + (void *)bh->b_data;
 186                         for (i = 4 ; i < 16 ; i++, current_minor++) {
 187                                 p--;
 188                                 if ((current_minor & 0x3f) >= 60)
 189                                         break;
 190                                 if (!(p->start_sect && p->nr_sects))
 191                                         continue;
 192                                 hd[current_minor].start_sect = p->start_sect;
 193                                 hd[current_minor].nr_sects = p->nr_sects;
 194                                 printk(" DM part %d start %d size %d end %d\n\r",
 195                                        current_minor,
 196                                        hd[current_minor].start_sect, 
 197                                        hd[current_minor].nr_sects,
 198                                        hd[current_minor].start_sect + 
 199                                        hd[current_minor].nr_sects);
 200                         }
 201                 }
 202         } else
 203                 printk("Bad partition table on dev %04x\n",dev);
 204         brelse(bh);
 205 }
 206 
 207 /* This may be used only once, enforced by 'static int callable' */
 208 int sys_setup(void * BIOS)
     /* [previous][next][first][last][top][bottom][index][help] */
 209 {
 210         static int callable = 1;
 211         int i,drive;
 212         unsigned char cmos_disks;
 213 
 214         if (!callable)
 215                 return -1;
 216         callable = 0;
 217 #ifndef HD_TYPE
 218         for (drive=0 ; drive<2 ; drive++) {
 219                 hd_info[drive].cyl = *(unsigned short *) BIOS;
 220                 hd_info[drive].head = *(unsigned char *) (2+BIOS);
 221                 hd_info[drive].wpcom = *(unsigned short *) (5+BIOS);
 222                 hd_info[drive].ctl = *(unsigned char *) (8+BIOS);
 223                 hd_info[drive].lzone = *(unsigned short *) (12+BIOS);
 224                 hd_info[drive].sect = *(unsigned char *) (14+BIOS);
 225                 BIOS += 16;
 226         }
 227 
 228         /*
 229                 We querry CMOS about hard disks : it could be that 
 230                 we have a SCSI/ESDI/etc controller that is BIOS
 231                 compatable with ST-506, and thus showing up in our
 232                 BIOS table, but not register compatable, and therefore
 233                 not present in CMOS.
 234 
 235                 Furthurmore, we will assume that our ST-506 drives
 236                 <if any> are the primary drives in the system, and 
 237                 the ones reflected as drive 1 or 2.
 238 
 239                 The first drive is stored in the high nibble of CMOS
 240                 byte 0x12, the second in the low nibble.  This will be
 241                 either a 4 bit drive type or 0xf indicating use byte 0x19 
 242                 for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS.
 243 
 244                 Needless to say, a non-zero value means we have 
 245                 an AT controller hard disk for that drive.
 246 
 247                 
 248         */
 249 
 250         if ((cmos_disks = CMOS_READ(0x12)) & 0xf0)
 251                 if (cmos_disks & 0x0f)
 252                         NR_HD = 2;
 253                 else
 254                         NR_HD = 1;
 255         else
 256                 NR_HD = 0;
 257 #endif
 258         for (i = 0 ; i < (MAX_HD<<6) ; i++) {
 259                 hd[i].start_sect = 0;
 260                 hd[i].nr_sects = 0;
 261         }
 262         for (i = 0 ; i < NR_HD ; i++)
 263                 hd[i<<6].nr_sects = hd_info[i].head*
 264                                 hd_info[i].sect*hd_info[i].cyl;
 265         for (drive=0 ; drive<NR_HD ; drive++) {
 266                 current_minor = 1+(drive<<6);
 267                 check_partition(0x0300+(drive<<6));
 268         }
 269         for (i=0 ; i<(MAX_HD<<6) ; i++)
 270                 hd_sizes[i] = hd[i].nr_sects>>1 ;
 271         blk_size[MAJOR_NR] = hd_sizes;
 272         if (NR_HD)
 273                 printk("Partition table%s ok.\n\r",(NR_HD>1)?"s":"");
 274         rd_load();
 275         mount_root();
 276         return (0);
 277 }
 278 
 279 static int controller_ready(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 280 {
 281         int retries = 100000;
 282 
 283         while (--retries && (inb_p(HD_STATUS)&0x80))
 284                 /* nothing */;
 285         if (!retries)
 286                 printk("controller_ready: status = %02x\n\r",
 287                         (unsigned char) inb_p(HD_STATUS));
 288         return (retries);
 289 }
 290 
 291 static int win_result(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 292 {
 293         int i=inb_p(HD_STATUS);
 294 
 295         if ((i & (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT))
 296                 == (READY_STAT | SEEK_STAT))
 297                 return(0); /* ok */
 298         if (i&1)
 299                 i=inb(HD_ERROR);
 300         return (1);
 301 }
 302 
 303 static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect,
     /* [previous][next][first][last][top][bottom][index][help] */
 304                 unsigned int head,unsigned int cyl,unsigned int cmd,
 305                 void (*intr_addr)(void))
 306 {
 307         unsigned short port;
 308 
 309         if (drive>1 || head>15)
 310                 panic("Trying to write bad sector");
 311         if (reset || !controller_ready()) {
 312                 reset = 1;
 313                 return;
 314         }
 315         SET_INTR(intr_addr);
 316         outb_p(hd_info[drive].ctl,HD_CMD);
 317         port=HD_DATA;
 318         outb_p(hd_info[drive].wpcom>>2,++port);
 319         outb_p(nsect,++port);
 320         outb_p(sect,++port);
 321         outb_p(cyl,++port);
 322         outb_p(cyl>>8,++port);
 323         outb_p(0xA0|(drive<<4)|head,++port);
 324         outb(cmd,++port);
 325 }
 326 
 327 static int drive_busy(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 328 {
 329         unsigned int i;
 330         unsigned char c;
 331 
 332         for (i = 0; i < 500000 ; i++) {
 333                 c = inb_p(HD_STATUS);
 334                 c &= (BUSY_STAT | READY_STAT | SEEK_STAT);
 335                 if (c == (READY_STAT | SEEK_STAT))
 336                         return 0;
 337         }
 338         printk("HD controller times out, c=%02x\n\r",c);
 339         return(1);
 340 }
 341 
 342 static void reset_controller(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 343 {
 344         int     i;
 345 
 346         outb(4,HD_CMD);
 347         for(i = 0; i < 1000; i++) nop();
 348         outb(hd_info[0].ctl & 0x0f ,HD_CMD);
 349         if (drive_busy())
 350                 printk("HD-controller still busy\n\r");
 351         if ((i = inb(HD_ERROR)) != 1)
 352                 printk("HD-controller reset failed: %02x\n\r",i);
 353 }
 354 
 355 static void reset_hd(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 356 {
 357         static int i;
 358 
 359 repeat:
 360         if (reset) {
 361                 reset = 0;
 362                 i = -1;
 363                 reset_controller();
 364         } else if (win_result()) {
 365                 bad_rw_intr();
 366                 if (reset)
 367                         goto repeat;
 368         }
 369         i++;
 370         if (i < NR_HD) {
 371                 hd_out(i,hd_info[i].sect,hd_info[i].sect,hd_info[i].head-1,
 372                         hd_info[i].cyl,WIN_SPECIFY,&reset_hd);
 373                 if (reset)
 374                         goto repeat;
 375         } else
 376                 do_hd_request();
 377 }
 378 
 379 /*
 380  * Ok, don't know what to do with the unexpected interrupts: on some machines
 381  * doing a reset and a retry seems to result in an eternal loop. Right now I
 382  * ignore it, and just set the timeout.
 383  */
 384 void unexpected_hd_interrupt(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 385 {
 386         printk("Unexpected HD interrupt\n\r");
 387         SET_TIMER;
 388 #if 0
 389         reset = 1;
 390         do_hd_request();
 391 #endif
 392 }
 393 
 394 static void bad_rw_intr(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 395 {
 396         if (!CURRENT)
 397                 return;
 398         if (++CURRENT->errors >= MAX_ERRORS)
 399                 end_request(0);
 400         if (CURRENT->errors > MAX_ERRORS/2)
 401                 reset = 1;
 402         else
 403                 recalibrate = 1;
 404 }
 405 
 406 static void read_intr(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 407 {
 408         SET_INTR(&read_intr);
 409         if (win_result()) {
 410                 SET_INTR(NULL);
 411                 bad_rw_intr();
 412                 do_hd_request();
 413                 return;
 414         }
 415         port_read(HD_DATA,CURRENT->buffer,256);
 416         CURRENT->errors = 0;
 417         CURRENT->buffer += 512;
 418         CURRENT->sector++;
 419         if (--CURRENT->nr_sectors)
 420                 return;
 421         SET_INTR(NULL);
 422         end_request(1);
 423         do_hd_request();
 424 }
 425 
 426 static void write_intr(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 427 {
 428         if (win_result()) {
 429                 bad_rw_intr();
 430                 do_hd_request();
 431                 return;
 432         }
 433         if (--CURRENT->nr_sectors) {
 434                 CURRENT->sector++;
 435                 CURRENT->buffer += 512;
 436                 SET_INTR(&write_intr);
 437                 port_write(HD_DATA,CURRENT->buffer,256);
 438                 return;
 439         }
 440         end_request(1);
 441         do_hd_request();
 442 }
 443 
 444 static void recal_intr(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 445 {
 446         if (win_result())
 447                 bad_rw_intr();
 448         do_hd_request();
 449 }
 450 
 451 /*
 452  * This is another of the error-routines I don't know what to do with. The
 453  * best idea seems to just set reset, and start all over again.
 454  */
 455 static void hd_times_out(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 456 {       
 457         do_hd = NULL;
 458         reset = 1;
 459         if (!CURRENT)
 460                 return;
 461         printk("HD timeout\n\r");
 462         cli();
 463         if (++CURRENT->errors >= MAX_ERRORS)
 464                 end_request(0);
 465         do_hd_request();
 466 }
 467 
 468 static void do_hd_request(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 469 {
 470         int i,r;
 471         unsigned int block,dev;
 472         unsigned int sec,head,cyl;
 473         unsigned int nsect;
 474 
 475         INIT_REQUEST;
 476         dev = MINOR(CURRENT->dev);
 477         block = CURRENT->sector;
 478         nsect = CURRENT->nr_sectors;
 479         if (dev >= (NR_HD<<6) || block+nsect > hd[dev].nr_sects) {
 480                 end_request(0);
 481                 goto repeat;
 482         }
 483         block += hd[dev].start_sect;
 484         dev >>= 6;
 485         sec = block % hd_info[dev].sect;
 486         block /= hd_info[dev].sect;
 487         head = block % hd_info[dev].head;
 488         cyl = block / hd_info[dev].head;
 489         sec++;
 490         if (reset) {
 491                 recalibrate = 1;
 492                 reset_hd();
 493                 return;
 494         }
 495         if (recalibrate) {
 496                 recalibrate = 0;
 497                 hd_out(dev,hd_info[dev].sect,0,0,0,
 498                         WIN_RESTORE,&recal_intr);
 499                 if (reset)
 500                         goto repeat;
 501                 return;
 502         }       
 503         if (CURRENT->cmd == WRITE) {
 504                 hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr);
 505                 if (reset)
 506                         goto repeat;
 507                 for(i=0 ; i<10000 && !(r=inb_p(HD_STATUS)&DRQ_STAT) ; i++)
 508                         /* nothing */ ;
 509                 if (!r) {
 510                         bad_rw_intr();
 511                         goto repeat;
 512                 }
 513                 port_write(HD_DATA,CURRENT->buffer,256);
 514         } else if (CURRENT->cmd == READ) {
 515                 hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr);
 516                 if (reset)
 517                         goto repeat;
 518         } else
 519                 panic("unknown hd-command");
 520 }
 521 
 522 void hd_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 523 {
 524         blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
 525         set_intr_gate(0x2E,&hd_interrupt);
 526         outb_p(inb_p(0x21)&0xfb,0x21);
 527         outb(inb_p(0xA1)&0xbf,0xA1);
 528         timer_table[HD_TIMER].fn = hd_times_out;
 529 }
 530 
 531 int hd_ioctl(int dev, int cmd, int arg)
     /* [previous][next][first][last][top][bottom][index][help] */
 532 {
 533         struct hd_geometry *loc = (void *) arg;
 534 
 535         if (!loc)
 536                 return -EINVAL;
 537         dev = MINOR(dev) >> 6;
 538         if (dev >= NR_HD)
 539                 return -EINVAL;
 540 
 541         switch (cmd) {
 542                 case HDIO_REQ:
 543                         put_fs_byte(hd_info[dev].head,
 544                                 (char *) &loc->heads);
 545                         put_fs_byte(hd_info[dev].sect,
 546                                 (char *) &loc->sectors);
 547                         put_fs_word(hd_info[dev].cyl,
 548                                 (short *) &loc->cylinders);
 549                         return 0;
 550                 default:
 551                         return -EINVAL;
 552         }
 553 }

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