root/drivers/block/promise.c

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

DEFINITIONS

This source file includes following definitions.
  1. promise_selectproc
  2. promise_cmd
  3. setup_dc4030
  4. init_dc4030
  5. promise_read_intr
  6. promise_write_pollfunc
  7. promise_write
  8. do_promise_io

   1 /*
   2  *  linux/drivers/block/promise.c       Version 0.04  Mar 15, 1996
   3  *
   4  *  Copyright (C) 1995-1996  Linus Torvalds & authors (see below)
   5  */
   6 
   7 /*
   8  *  Principal Author/Maintainer:  peterd@pnd-pc.demon.co.uk
   9  *
  10  *  This file provides support for the second port and cache of Promise
  11  *  IDE interfaces, e.g. DC4030, DC5030.
  12  *
  13  *  Thanks are due to Mark Lord for advice and patiently answering stupid
  14  *  questions, and all those mugs^H^H^H^Hbrave souls who've tested this.
  15  *
  16  *  Version 0.01        Initial version, #include'd in ide.c rather than
  17  *                      compiled separately.
  18  *                      Reads use Promise commands, writes as before. Drives
  19  *                      on second channel are read-only.
  20  *  Version 0.02        Writes working on second channel, reads on both
  21  *                      channels. Writes fail under high load. Suspect
  22  *                      transfers of >127 sectors don't work.
  23  *  Version 0.03        Brought into line with ide.c version 5.27.
  24  *                      Other minor changes.
  25  *  Version 0.04        Updated for ide.c version 5.30
  26  *                      Changed initialization strategy
  27  *  Version 0.05        Kernel integration.  -ml
  28  */
  29 
  30 
  31 /*
  32  * From:  'peterd@pnd-pc.demon.co.uk'
  33  *
  34  * Here's another version of the Promise driver for DC4030VL2 cards.
  35  * There have been few substantive changes to the code, but it is now in
  36  * line with the more recent ide.c changes, and is somewhat more configurable.
  37  *
  38  * Once you've compiled it in, you'll have to also enable the interface
  39  * setup routine from the kernel command line, as in 
  40  *
  41  *      'linux ide0=dc4030'
  42  *
  43  * As before, it seems that somewhere around 3Megs when writing, bad things
  44  * start to happen [timeouts/retries -ml]. If anyone can give me more feedback,
  45  * I'd really appreciate it.  [email: peterd@pnd-pc.demon.co.uk]
  46  *
  47  */
  48 
  49 
  50 #undef REALLY_SLOW_IO           /* most systems can safely undef this */
  51 
  52 #include <linux/types.h>
  53 #include <linux/kernel.h>
  54 #include <linux/delay.h>
  55 #include <linux/timer.h>
  56 #include <linux/mm.h>
  57 #include <linux/ioport.h>
  58 #include <linux/blkdev.h>
  59 #include <linux/hdreg.h>
  60 #include <asm/io.h>
  61 #include "ide.h"
  62 #include "promise.h"
  63 
  64 /* This is needed as the controller may not interrupt if the required data is
  65 available in the cache. We have to simulate an interrupt. Ugh! */
  66 
  67 extern void ide_intr(int, void *dev_id, struct pt_regs*);
  68 
  69 /*
  70  * promise_selectproc() is invoked by ide.c
  71  * in preparation for access to the specified drive.
  72  */
  73 static void promise_selectproc (ide_drive_t *drive)
     /* [previous][next][first][last][top][bottom][index][help] */
  74 {
  75         unsigned int number;
  76 
  77         OUT_BYTE(drive->select.all,IDE_SELECT_REG);
  78         udelay(1);      /* paranoia */
  79         number = ((HWIF(drive)->is_promise2)<<1) + drive->select.b.unit;
  80         OUT_BYTE(number,IDE_FEATURE_REG);
  81 }
  82 
  83 /*
  84  * promise_cmd handles the set of vendor specific commands that are initiated
  85  * by command F0. They all have the same success/failure notification.
  86  */
  87 int promise_cmd(ide_drive_t *drive, byte cmd)
     /* [previous][next][first][last][top][bottom][index][help] */
  88 {
  89         unsigned long timeout, timer;
  90         byte status_val;
  91 
  92         promise_selectproc(drive);      /* redundant? */
  93         OUT_BYTE(0xF3,IDE_SECTOR_REG);
  94         OUT_BYTE(cmd,IDE_SELECT_REG);
  95         OUT_BYTE(PROMISE_EXTENDED_COMMAND,IDE_COMMAND_REG);
  96         timeout = HZ * 10;
  97         timeout += jiffies;
  98         do {
  99                 if(jiffies > timeout) {
 100                         return 2; /* device timed out */
 101                 }
 102                 /* This is out of delay_10ms() */
 103                 /* Delays at least 10ms to give interface a chance */
 104                 timer = jiffies + (HZ + 99)/100 + 1;
 105                 while (timer > jiffies);
 106                 status_val = IN_BYTE(IDE_SECTOR_REG);
 107         } while (status_val != 0x50 && status_val != 0x70);
 108 
 109         if(status_val == 0x50)
 110                 return 0; /* device returned success */
 111         else
 112                 return 1; /* device returned failure */
 113 }
 114 
 115 ide_hwif_t *hwif_required = NULL;
 116 
 117 void setup_dc4030 (ide_hwif_t *hwif)
     /* [previous][next][first][last][top][bottom][index][help] */
 118 {
 119     hwif_required = hwif;
 120 }
 121 
 122 /*
 123 init_dc4030: Test for presence of a Promise caching controller card.
 124 Returns: 0 if no Promise card present at this io_base
 125          1 if Promise card found
 126 */
 127 int init_dc4030 (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 128 {
 129         ide_hwif_t *hwif = hwif_required;
 130         ide_drive_t *drive;
 131         ide_hwif_t *second_hwif;
 132         struct dc_ident ident;
 133         int i;
 134         
 135         if (!hwif) return 0;
 136 
 137         drive = &hwif->drives[0];
 138         second_hwif = &ide_hwifs[hwif->index+1];
 139         if(hwif->is_promise2) /* we've already been found ! */
 140             return 1;
 141 
 142         if(IN_BYTE(IDE_NSECTOR_REG) == 0xFF || IN_BYTE(IDE_SECTOR_REG) == 0xFF)
 143         {
 144             return 0;
 145         }
 146         OUT_BYTE(0x08,IDE_CONTROL_REG);
 147         if(promise_cmd(drive,PROMISE_GET_CONFIG)) {
 148             return 0;
 149         }
 150         if(ide_wait_stat(drive,DATA_READY,BAD_W_STAT,WAIT_DRQ)) {
 151             printk("%s: Failed Promise read config!\n",hwif->name);
 152             return 0;
 153         }
 154         ide_input_data(drive,&ident,SECTOR_WORDS);
 155         if(ident.id[1] != 'P' || ident.id[0] != 'T') {
 156             return 0;
 157         }
 158         printk("%s: Promise caching controller, ",hwif->name);
 159         switch(ident.type) {
 160             case 0x43:  printk("DC4030VL, "); break;
 161             default:    printk("unknown - type 0x%02x - please report!, "
 162                                ,ident.type);
 163                         return 0;
 164         }
 165         printk("%dKB cache, ",(int)ident.cache_mem);
 166         switch(ident.irq) {
 167             case 0x00: hwif->irq = 14; break;
 168             case 0x01: hwif->irq = 12; break;
 169             default:   hwif->irq = 15; break;
 170         }
 171         printk("on IRQ %d\n",hwif->irq);
 172         hwif->chipset    = second_hwif->chipset    = ide_promise;
 173         hwif->selectproc = second_hwif->selectproc = &promise_selectproc;
 174         second_hwif->is_promise2 = 1;
 175         second_hwif->io_base = hwif->io_base;
 176         second_hwif->ctl_port = hwif->ctl_port; 
 177         second_hwif->irq = hwif->irq;
 178         for (i=0; i<2 ; i++) {
 179             hwif->drives[i].io_32bit = 3;
 180             second_hwif->drives[i].io_32bit = 3;
 181             if(!ident.current_tm[i+2].cyl) second_hwif->drives[i].noprobe=1;
 182         }
 183         return 1;
 184 }
 185 
 186 /*
 187  * promise_read_intr() is the handler for disk read/multread interrupts
 188  */
 189 static void promise_read_intr (ide_drive_t *drive)
     /* [previous][next][first][last][top][bottom][index][help] */
 190 {
 191         byte stat;
 192         int i;
 193         unsigned int sectors_left, sectors_avail, nsect;
 194         struct request *rq;
 195 
 196         if (!OK_STAT(stat=GET_STAT(),DATA_READY,BAD_R_STAT)) {
 197                 ide_error(drive, "promise_read_intr", stat);
 198                 return;
 199         }
 200 
 201 read_again:
 202         do {
 203             sectors_left = IN_BYTE(IDE_NSECTOR_REG);
 204             IN_BYTE(IDE_SECTOR_REG);
 205         } while (IN_BYTE(IDE_NSECTOR_REG) != sectors_left);
 206         rq = HWGROUP(drive)->rq;
 207         sectors_avail = rq->nr_sectors - sectors_left;
 208 
 209 read_next:
 210         rq = HWGROUP(drive)->rq;
 211         if ((nsect = rq->current_nr_sectors) > sectors_avail)
 212                 nsect = sectors_avail;
 213         sectors_avail -= nsect;
 214         ide_input_data(drive, rq->buffer, nsect * SECTOR_WORDS);
 215 #ifdef DEBUG
 216         printk("%s:  promise_read: sectors(%ld-%ld), buffer=0x%08lx, "
 217                "remaining=%ld\n", drive->name, rq->sector, rq->sector+nsect-1, 
 218                (unsigned long) rq->buffer+(nsect<<9), rq->nr_sectors-nsect);
 219 #endif
 220         rq->sector += nsect;
 221         rq->buffer += nsect<<9;
 222         rq->errors = 0;
 223         i = (rq->nr_sectors -= nsect);
 224         if ((rq->current_nr_sectors -= nsect) <= 0)
 225                 ide_end_request(1, HWGROUP(drive));
 226         if (i > 0) {
 227                 if (sectors_avail)
 228                     goto read_next;
 229                 stat = GET_STAT();
 230                 if(stat & DRQ_STAT)
 231                     goto read_again;
 232                 if(stat & BUSY_STAT) {
 233                     ide_set_handler (drive, &promise_read_intr, WAIT_CMD);
 234                     return;
 235                 }
 236                 printk("Ah! promise read intr: sectors left !DRQ !BUSY\n");
 237                 ide_error(drive, "promise read intr", stat);
 238         }
 239 }
 240 
 241 /*
 242  * promise_write_pollfunc() is the handler for disk write completion polling.
 243  */
 244 static void promise_write_pollfunc (ide_drive_t *drive)
     /* [previous][next][first][last][top][bottom][index][help] */
 245 {
 246         int i;
 247         ide_hwgroup_t *hwgroup = HWGROUP(drive);
 248         struct request *rq;
 249 
 250         if (IN_BYTE(IDE_NSECTOR_REG) != 0) {
 251             if (jiffies < hwgroup->poll_timeout) {
 252                 ide_set_handler (drive, &promise_write_pollfunc, 1);
 253                 return; /* continue polling... */
 254             }
 255             printk("%s: write timed-out!\n",drive->name);
 256             ide_error (drive, "write timeout", GET_STAT());
 257             return;
 258         }
 259         
 260         ide_multwrite(drive, 4);
 261         rq = hwgroup->rq;
 262         for (i = rq->nr_sectors; i > 0;) {
 263             i -= rq->current_nr_sectors;
 264             ide_end_request(1, hwgroup);
 265         }
 266         return;
 267 }
 268 
 269 /*
 270  * promise_write() transfers a block of one or more sectors of data to a
 271  * drive as part of a disk write operation. All but 4 sectors are transfered
 272  * in the first attempt, then the interface is polled (nicely!) for completion
 273  * before the final 4 sectors are transfered. Don't ask me why, but this is
 274  * how it's done in the drivers for other O/Ses. There is no interrupt
 275  * generated on writes, which is why we have to do it like this.
 276  */
 277 static void promise_write (ide_drive_t *drive)
     /* [previous][next][first][last][top][bottom][index][help] */
 278 {
 279     ide_hwgroup_t *hwgroup = HWGROUP(drive);
 280     struct request *rq = &hwgroup->wrq;
 281     int i;
 282 
 283     if (rq->nr_sectors > 4) {
 284         ide_multwrite(drive, rq->nr_sectors - 4);
 285         hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;
 286         ide_set_handler (drive, &promise_write_pollfunc, 1);
 287         return;
 288     } else {
 289         ide_multwrite(drive, rq->nr_sectors);
 290         rq = hwgroup->rq;
 291         for (i = rq->nr_sectors; i > 0;) {
 292             i -= rq->current_nr_sectors;
 293             ide_end_request(1, hwgroup);
 294         }
 295     }
 296 }
 297 
 298 /*
 299  * do_promise_rw_disk() issues READ and WRITE commands to a
 300  * disk on a promise controller, using LBA to address sectors.  It also
 301  * takes care of issuing special DRIVE_CMDs.
 302  */
 303 void do_promise_io (ide_drive_t *drive, struct request *rq)
     /* [previous][next][first][last][top][bottom][index][help] */
 304 {
 305         unsigned long timeout;
 306         unsigned short io_base = HWIF(drive)->io_base;
 307         byte stat;
 308 
 309         if (rq->cmd == READ) {
 310             ide_set_handler(drive, &promise_read_intr, WAIT_CMD);
 311             OUT_BYTE(PROMISE_READ, io_base+IDE_COMMAND_OFFSET);
 312             /* The card's behaviour is odd at this point. If the data is
 313                available, DRQ will be true, and no interrupt will be
 314                generated by the card. If this is the case, we need to simulate
 315                an interrupt. Ugh! Otherwise, if an interrupt will occur, bit0
 316                of the SELECT register will be high, so we can just return and
 317                be interrupted.*/
 318             timeout = jiffies + HZ/20; /* 50ms wait */
 319             do {
 320                 stat=GET_STAT();
 321                 if(stat & DRQ_STAT) {
 322                     ide_intr(HWIF(drive)->irq,NULL,NULL);
 323                     return;
 324                 }
 325                 if(IN_BYTE(io_base+IDE_SELECT_OFFSET) & 0x01)
 326                     return;
 327             } while (jiffies < timeout);
 328             printk("%s: reading: No DRQ and not waiting - Odd!\n",
 329                    drive->name);
 330             return;
 331         }
 332         if (rq->cmd == WRITE) {
 333             OUT_BYTE(PROMISE_WRITE, io_base+IDE_COMMAND_OFFSET);
 334             if (ide_wait_stat(drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
 335                 printk("%s: no DRQ after issuing PROMISE_WRITE\n", drive->name);
 336                 return;
 337             }
 338             if (!drive->unmask)
 339                 cli();
 340             HWGROUP(drive)->wrq = *rq; /* scratchpad */
 341             promise_write(drive);
 342             return;
 343         }
 344         printk("%s: bad command: %d\n", drive->name, rq->cmd);
 345         ide_end_request(0, HWGROUP(drive));
 346 }

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