root/kernel/blk_drv/scsi/ultrastor.c

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

DEFINITIONS

This source file includes following definitions.
  1. ultrastor_detect
  2. ultrastor_info
  3. build_sg_list
  4. ultrastor_queuecommand
  5. ultrastor_abort
  6. ultrastor_reset
  7. ultrastor_biosparam
  8. ultrastor_interrupt

   1 /*
   2  *      ultrastor.c     Copyright (C) 1992 David B. Gentzel
   3  *      Low-level SCSI driver for UltraStor 14F
   4  *      by David B. Gentzel, Whitfield Software Services, Carnegie, PA
   5  *          (gentzel@nova.enet.dec.com)
   6  *  scatter/gather added by Scott Taylor (n217cg@tamuts.tamu.edu)
   7  *      Thanks to UltraStor for providing the necessary documentation
   8  */
   9 
  10 /*
  11  * TODO:
  12  *      1. Cleanup error handling & reporting.
  13  *      2. Find out why scatter/gather is limited to 16 requests per command.
  14  *      3. Add multiple outstanding requests.
  15  *      4. See if we can make good use of having more than one command per lun.
  16  *      5. Test/improve/fix abort & reset functions.
  17  *      6. Look at command linking (mscp.command_link and
  18  *         mscp.command_link_id).
  19  */
  20 
  21 /*
  22  * NOTES:
  23  *    The UltraStor 14F is one of a family of intelligent, high performance
  24  *    SCSI-2 host adapters.  They all support command queueing and
  25  *    scatter/gather I/O.  Some of them can also emulate the standard
  26  *    WD1003 interface for use with OS's which don't support SCSI.
  27  *    Here is the scoop on the various models:
  28  *      14F - ISA first-party DMA HA with floppy support and WD1003 emulation.
  29  *      14N - ISA HA with floppy support.  I think that this is a non-DMA
  30  *            HA.  Nothing further known.
  31  *      24F - EISA Bus Master HA with floppy support and WD1003 emulation.
  32  *      34F - VL-Bus Bus Master HA with floppy support (no WD1003 emulation).
  33  *
  34  *    The 14F is supported by this driver.  An effort has been made to support
  35  *    the 34F.  It should work, but is untested.  The 24F does not work at
  36  *    present.
  37  *
  38  *    Places flagged with a triple question-mark are things which are either
  39  *    unfinished, questionable, or wrong.
  40  */
  41 
  42 #include <linux/stddef.h>
  43 #include <linux/string.h>
  44 #include <linux/sched.h>
  45 #include <linux/kernel.h>
  46 
  47 #include <asm/io.h>
  48 #include <asm/system.h>
  49 #include <asm/dma.h>
  50 
  51 #define ULTRASTOR_PRIVATE       /* Get the private stuff from ultrastor.h */
  52 #include "../blk.h"
  53 #include "scsi.h"
  54 #include "hosts.h"
  55 #include "ultrastor.h"
  56 
  57 #define ULTRASTOR_DEBUG 0
  58 
  59 #define VERSION "1.1 alpha"
  60 
  61 #define ARRAY_SIZE(arr) (sizeof (arr) / sizeof (arr)[0])
  62 #define BYTE(num, n) ((unsigned char)((unsigned int)(num) >> ((n) * 8)))
  63 
  64 /* Simply using "unsigned long" in these structures won't work as it causes
  65    alignment.  Perhaps the "aligned" attribute may be used in GCC 2.0 to get
  66    around this, but for now I use this hack. */
  67 typedef struct {
  68     unsigned char bytes[4];
  69 } Longword;
  70 
  71 /* Used to fetch the configuration info from the config i/o registers.  We
  72    then store (in a friendlier format) in config. */
  73 struct config_1 {
  74     unsigned char bios_segment: 3;
  75     unsigned char removable_disks_as_fixed: 1;
  76     unsigned char interrupt: 2;
  77     unsigned char dma_channel: 2;
  78 };
  79 struct config_2 {
  80     unsigned char ha_scsi_id: 3;
  81     unsigned char mapping_mode: 2;
  82     unsigned char bios_drive_number: 1;
  83     unsigned char tfr_port: 2;
  84 };
  85 
  86 /* Used to store configuration info read from config i/o registers.  Most of
  87    this is not used yet, but might as well save it. */
  88 struct config {
  89     const void *bios_segment;
  90     unsigned short port_address;
  91     unsigned char interrupt: 4;
  92     unsigned char dma_channel: 3;
  93     unsigned char bios_drive_number: 1;
  94     unsigned char heads: 6;
  95     unsigned char sectors: 6;
  96     unsigned char ha_scsi_id: 3;
  97     unsigned char subversion: 4;
  98 };
  99 
 100 /* MailBox SCSI Command Packet.  Basic command structure for communicating
 101    with controller. */
 102 struct mscp {
 103     unsigned char opcode: 3;            /* type of command */
 104     unsigned char xdir: 2;              /* data transfer direction */
 105     unsigned char dcn: 1;               /* disable disconnect */
 106     unsigned char ca: 1;                /* use cache (if available) */
 107     unsigned char sg: 1;                /* scatter/gather operation */
 108     unsigned char target_id: 3;         /* target SCSI id */
 109     unsigned char ch_no: 2;             /* SCSI channel (always 0 for 14f) */
 110     unsigned char lun: 3;               /* logical unit number */
 111     Longword transfer_data;             /* transfer data pointer */
 112     Longword transfer_data_length;      /* length in bytes */
 113     Longword command_link;              /* for linking command chains */
 114     unsigned char scsi_command_link_id; /* identifies command in chain */
 115     unsigned char number_of_sg_list;    /* (if sg is set) 8 bytes per list */
 116     unsigned char length_of_sense_byte;
 117     unsigned char length_of_scsi_cdbs;  /* 6, 10, or 12 */
 118     unsigned char scsi_cdbs[12];        /* SCSI commands */
 119     unsigned char adapter_status;       /* non-zero indicates HA error */
 120     unsigned char target_status;        /* non-zero indicates target error */
 121     Longword sense_data;
 122 };
 123 
 124 /* The 14F uses an array of unaligned 4-byte ints for its scatter/gather list. */
 125 typedef struct {
 126         Longword address;
 127         Longword num_bytes;
 128 } ultrastor_sg_list;
 129 
 130 /* This is our semaphore for mscp block availability */
 131 int mscp_free = TRUE;
 132 
 133 /* Allowed BIOS base addresses for 14f (NULL indicates reserved) */
 134 static const void *const bios_segment_table_14f[8] = {
 135     NULL,            (void *)0xC4000, (void *)0xC8000, (void *)0xCC000,
 136     (void *)0xD0000, (void *)0xD4000, (void *)0xD8000, (void *)0xDC000,
 137 };
 138 
 139 /* Allowed IRQs for 14f */
 140 static const unsigned char interrupt_table_14f[4] = { 15, 14, 11, 10 };
 141 
 142 /* Allowed DMA channels for 14f (0 indicates reserved) */
 143 static const unsigned char dma_channel_table_14f[4] = { 5, 6, 7, 0 };
 144 
 145 /* Head/sector mappings allowed by 14f */
 146 static const struct {
 147     unsigned char heads;
 148     unsigned char sectors;
 149 } mapping_table_14f[4] = { { 16, 63 }, { 64, 32 }, { 64, 63 }, { 0, 0 } };
 150 
 151 /* Subversions of the 14F */
 152 static const char *const subversion_names[] = { "14F", "34F" };
 153 
 154 /* Config info */
 155 static struct config config;
 156 
 157 /* Our index in the host adapter array maintained by higher-level driver */
 158 static int host_number;
 159 
 160 /* PORT_ADDRESS is first port address used for i/o of messages. */
 161 #ifdef PORT_OVERRIDE
 162 # define PORT_ADDRESS PORT_OVERRIDE
 163 #else
 164 # define PORT_ADDRESS (config.port_address)
 165 #endif
 166 
 167 static volatile int aborted = 0;
 168 
 169 #ifndef PORT_OVERRIDE
 170 /* ??? A probe of address 0x310 screws up NE2000 cards */
 171 static const unsigned short ultrastor_ports_14f[] = {
 172     0x330, 0x340, /*0x310,*/ 0x230, 0x240, 0x210, 0x130, 0x140,
 173 };
 174 #endif
 175 
 176 static void ultrastor_interrupt(int cpl);
 177 static inline void build_sg_list(Scsi_Cmnd *SCpnt);
 178 
 179 static void (*ultrastor_done)(Scsi_Cmnd *) = 0;
 180 static Scsi_Cmnd *SCint = NULL;
 181 
 182 int ultrastor_detect(int hostnum)
     /* [previous][next][first][last][top][bottom][index][help] */
 183 {
 184     size_t i;
 185     unsigned char in_byte, version_byte = 0;
 186     struct config_1 config_1;
 187     struct config_2 config_2;
 188 
 189 #if (ULTRASTOR_DEBUG & UD_DETECT)
 190     printk("US14F: detect: called\n");
 191 #endif
 192 
 193 #ifndef PORT_OVERRIDE
 194     PORT_ADDRESS = 0;
 195     for (i = 0; i < ARRAY_SIZE(ultrastor_ports_14f); i++) {
 196         PORT_ADDRESS = ultrastor_ports_14f[i];
 197 #endif
 198 
 199 #if (ULTRASTOR_DEBUG & UD_DETECT)
 200         printk("US14F: detect: testing port address %03X\n", PORT_ADDRESS);
 201 #endif
 202 
 203         in_byte = inb(PRODUCT_ID(PORT_ADDRESS + 0));
 204         if (in_byte != US14F_PRODUCT_ID_0) {
 205 #if (ULTRASTOR_DEBUG & UD_DETECT)
 206 # ifdef PORT_OVERRIDE
 207             printk("US14F: detect: wrong product ID 0 - %02X\n", in_byte);
 208 # else
 209             printk("US14F: detect: no adapter at port %03X\n", PORT_ADDRESS);
 210 # endif
 211 #endif
 212 #ifdef PORT_OVERRIDE
 213             return FALSE;
 214 #else
 215             continue;
 216 #endif
 217         }
 218         in_byte = inb(PRODUCT_ID(PORT_ADDRESS + 1));
 219         /* Only upper nibble is significant for Product ID 1 */
 220         if ((in_byte & 0xF0) != US14F_PRODUCT_ID_1) {
 221 #if (ULTRASTOR_DEBUG & UD_DETECT)
 222 # ifdef PORT_OVERRIDE
 223             printk("US14F: detect: wrong product ID 1 - %02X\n", in_byte);
 224 # else
 225             printk("US14F: detect: no adapter at port %03X\n", PORT_ADDRESS);
 226 # endif
 227 #endif
 228 #ifdef PORT_OVERRIDE
 229             return FALSE;
 230 #else
 231             continue;
 232 #endif
 233         }
 234         version_byte = in_byte;
 235 #ifndef PORT_OVERRIDE
 236         break;
 237     }
 238     if (i == ARRAY_SIZE(ultrastor_ports_14f)) {
 239 # if (ULTRASTOR_DEBUG & UD_DETECT)
 240         printk("US14F: detect: no port address found!\n");
 241 # endif
 242         return FALSE;
 243     }
 244 #endif
 245 
 246 #if (ULTRASTOR_DEBUG & UD_DETECT)
 247     printk("US14F: detect: adapter found at port address %03X\n",
 248            PORT_ADDRESS);
 249 #endif
 250 
 251     /* All above tests passed, must be the right thing.  Get some useful
 252        info. */
 253     *(char *)&config_1 = inb(CONFIG(PORT_ADDRESS + 0));
 254     *(char *)&config_2 = inb(CONFIG(PORT_ADDRESS + 1));
 255     config.bios_segment = bios_segment_table_14f[config_1.bios_segment];
 256     config.interrupt = interrupt_table_14f[config_1.interrupt];
 257     config.ha_scsi_id = config_2.ha_scsi_id;
 258     config.heads = mapping_table_14f[config_2.mapping_mode].heads;
 259     config.sectors = mapping_table_14f[config_2.mapping_mode].sectors;
 260     config.bios_drive_number = config_2.bios_drive_number;
 261     config.subversion = (version_byte & 0x0F);
 262     if (config.subversion == U34F)
 263         config.dma_channel = 0;
 264     else
 265         config.dma_channel = dma_channel_table_14f[config_1.dma_channel];
 266 
 267     if (!config.bios_segment) {
 268 #if (ULTRASTOR_DEBUG & UD_DETECT)
 269         printk("US14F: detect: not detected.\n");
 270 #endif
 271         return FALSE;
 272     }
 273 
 274     /* Final consistancy check, verify previous info. */
 275     if (config.subversion != U34F)
 276         if (!config.dma_channel || !(config_2.tfr_port & 0x2)) {
 277 #if (ULTRASTOR_DEBUG & UD_DETECT)
 278             printk("US14F: detect: consistancy check failed\n");
 279 #endif
 280             return FALSE;
 281         }
 282 
 283     /* If we were TRULY paranoid, we could issue a host adapter inquiry
 284        command here and verify the data returned.  But frankly, I'm
 285        exhausted! */
 286 
 287     /* Finally!  Now I'm satisfied... */
 288 #if (ULTRASTOR_DEBUG & UD_DETECT)
 289     printk("US14F: detect: detect succeeded\n"
 290            "  Port address: %03X\n"
 291            "  BIOS segment: %05X\n"
 292            "  Interrupt: %u\n"
 293            "  DMA channel: %u\n"
 294            "  H/A SCSI ID: %u\n"
 295            "  Subversion: %u\n",
 296            PORT_ADDRESS, config.bios_segment, config.interrupt,
 297            config.dma_channel, config.ha_scsi_id, config.subversion);
 298 #endif
 299     host_number = hostnum;
 300     scsi_hosts[hostnum].this_id = config.ha_scsi_id;
 301     scsi_hosts[hostnum].unchecked_isa_dma = (config.subversion != U34F);
 302 
 303     if (request_irq(config.interrupt, ultrastor_interrupt)) {
 304         printk("Unable to allocate IRQ%u for UltraStor controller.\n",
 305                config.interrupt);
 306         return FALSE;
 307     }
 308     if (config.dma_channel && request_dma(config.dma_channel)) {
 309         printk("Unable to allocate DMA channel %u for UltraStor controller.\n",
 310                config.dma_channel);
 311         free_irq(config.interrupt);
 312         return FALSE;
 313     }
 314         scsi_hosts[hostnum].sg_tablesize = ULTRASTOR_14F_MAX_SG;
 315         printk("UltraStor: scatter/gather enabled.  Using %d SG lists.\n", ULTRASTOR_14F_MAX_SG);
 316 
 317     return TRUE;
 318 }
 319 
 320 const char *ultrastor_info(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 321 {
 322     static char buf[64];
 323 
 324     (void)sprintf(buf, "UltraStor %s SCSI @ Port %03X BIOS %05X IRQ%u DMA%u\n",
 325                   ((config.subversion < ARRAY_SIZE(subversion_names))
 326                    ? subversion_names[config.subversion] : "14F?"),
 327                   PORT_ADDRESS, (int)config.bios_segment, config.interrupt,
 328                   config.dma_channel);
 329     return buf;
 330 }
 331 
 332 static struct mscp mscp = {
 333     OP_SCSI, DTD_SCSI, 0, 1, 0          /* This stuff doesn't change */
 334 };
 335 
 336 static inline void build_sg_list(Scsi_Cmnd *SCpnt)
     /* [previous][next][first][last][top][bottom][index][help] */
 337 {
 338         ultrastor_sg_list *sglist;
 339         struct scatterlist *sl;
 340         long transfer_length = 0;
 341         int i;
 342 
 343         sl = (struct scatterlist *) SCpnt->request_buffer;
 344         SCpnt->host_scribble = scsi_malloc(512);
 345         if (SCpnt->host_scribble == NULL)
 346                 /* Not sure what to do here; just panic for now */
 347                 panic("US14F: Can't allocate DMA buffer for scatter-gather list!\n");
 348         /* Save ourselves some casts; can eliminate when we don't have to look at it anymore! */
 349         sglist = (ultrastor_sg_list *) SCpnt->host_scribble;
 350         for (i = 0; i < SCpnt->use_sg; i++) {
 351                 sglist[i].address = *(Longword *)&(sl[i].address);
 352                 sglist[i].num_bytes = *(Longword *)&(sl[i].length);
 353                 transfer_length += sl[i].length;
 354         }
 355         mscp.number_of_sg_list = (char) SCpnt->use_sg;
 356         mscp.transfer_data = *(Longword *)&sglist;
 357         /* ??? May not be necessary.  Docs are unclear as to whether transfer length field is */
 358         /* ignored or whether it should be set to the total number of bytes of the transfer.  */
 359         mscp.transfer_data_length = *(Longword *)&transfer_length;
 360 }
 361 
 362 int ultrastor_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
     /* [previous][next][first][last][top][bottom][index][help] */
 363 {
 364     unsigned char in_byte;
 365 
 366 #if (ULTRASTOR_DEBUG & UD_COMMAND)
 367     printk("US14F: queuecommand: called\n");
 368 #endif
 369 
 370         /* We want to be sure that a command queued while another command   */
 371         /* is running doesn't overwrite the mscp block until the running    */
 372         /* command is finished.  mscp_free is set in the interrupt handler. */
 373         /* I'm not sure if the upper level driver will send another command */
 374         /* with a command pending; this is just insurance.                  */
 375         while (1) {
 376                 cli();
 377                 if (mscp_free) {
 378                         mscp_free = FALSE;
 379                         sti();
 380                         break;
 381                 }
 382                 sti();
 383         }
 384     mscp.opcode = OP_SCSI;
 385     mscp.xdir = DTD_SCSI;
 386     mscp.dcn = FALSE;
 387     mscp.ca = TRUE;
 388     mscp.target_id = SCpnt->target;
 389     mscp.ch_no = 0;
 390     mscp.lun = SCpnt->lun;
 391         if (SCpnt->use_sg) {
 392                 /* Set scatter/gather flag in SCSI command packet */
 393                 mscp.sg = TRUE;
 394                 build_sg_list(SCpnt);
 395         }
 396         else {
 397                 /* Unset scatter/gather flag in SCSI command packet */
 398                 mscp.sg = FALSE;
 399                 mscp.transfer_data = *(Longword *)&SCpnt->request_buffer;
 400                 mscp.transfer_data_length = *(Longword *)&SCpnt->request_bufflen;
 401                 SCpnt->host_scribble = NULL;
 402         }
 403     memset(&mscp.command_link, 0, sizeof(mscp.command_link));   /*???*/
 404     mscp.scsi_command_link_id = 0;      /*???*/
 405     mscp.length_of_sense_byte = 0;      /*???*/
 406     mscp.length_of_scsi_cdbs = ((SCpnt->cmnd[0] <= 0x1F) ? 6 : 10);
 407     memcpy(mscp.scsi_cdbs, SCpnt->cmnd, mscp.length_of_scsi_cdbs);
 408     mscp.adapter_status = 0;
 409     mscp.target_status = 0;
 410     memset(&mscp.sense_data, 0, sizeof(mscp.sense_data));       /*???*/
 411 
 412     /* Find free OGM slot (OGMINT bit is 0) */
 413     do
 414         in_byte = inb_p(LCL_DOORBELL_INTR(PORT_ADDRESS));
 415     while (!aborted && (in_byte & 1));
 416     if (aborted) {
 417 #if (ULTRASTOR_DEBUG & (UD_COMMAND | UD_ABORT))
 418         printk("US14F: queuecommand: aborted\n");
 419 #endif
 420         /* ??? is this right? */
 421         return (aborted << 16);
 422     }
 423 
 424     /* Store pointer in OGM address bytes */
 425     outb_p(BYTE(&mscp, 0), OGM_DATA_PTR(PORT_ADDRESS + 0));
 426     outb_p(BYTE(&mscp, 1), OGM_DATA_PTR(PORT_ADDRESS + 1));
 427     outb_p(BYTE(&mscp, 2), OGM_DATA_PTR(PORT_ADDRESS + 2));
 428     outb_p(BYTE(&mscp, 3), OGM_DATA_PTR(PORT_ADDRESS + 3));
 429 
 430     /* Issue OGM interrupt */
 431     outb_p(0x1, LCL_DOORBELL_INTR(PORT_ADDRESS));
 432 
 433     ultrastor_done = done;
 434     SCint = SCpnt;
 435 
 436 #if (ULTRASTOR_DEBUG & UD_COMMAND)
 437     printk("US14F: queuecommand: returning\n");
 438 #endif
 439 
 440     return 0;
 441 }
 442 
 443 int ultrastor_abort(Scsi_Cmnd *SCpnt, int code)
     /* [previous][next][first][last][top][bottom][index][help] */
 444 {
 445 #if (ULTRASTOR_DEBUG & UD_ABORT)
 446     printk("US14F: abort: called\n");
 447 #endif
 448 
 449     aborted = (code ? code : DID_ABORT);
 450 
 451         /* Free DMA buffer used for scatter/gather list */
 452         if (SCpnt->host_scribble)
 453                 scsi_free(SCpnt->host_scribble, 512);
 454 
 455         /* Free up mscp block for next command */
 456         mscp_free = TRUE;
 457 
 458 #if (ULTRASTOR_DEBUG & UD_ABORT)
 459     printk("US14F: abort: returning\n");
 460 #endif
 461 
 462     return 0;
 463 }
 464 
 465 int ultrastor_reset(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 466 {
 467     unsigned char in_byte;
 468 
 469 #if (ULTRASTOR_DEBUG & UD_RESET)
 470     printk("US14F: reset: called\n");
 471 #endif
 472 
 473         /* ??? SCSI bus reset causes problems on some systems. */
 474 #if 0
 475     /* Issue SCSI BUS reset */
 476     outb_p(0x20, LCL_DOORBELL_INTR(PORT_ADDRESS));
 477 
 478     /* Wait for completion... */
 479     do
 480         in_byte = inb_p(LCL_DOORBELL_INTR(PORT_ADDRESS));
 481     while (in_byte & 0x20);
 482 
 483     aborted = DID_RESET;
 484 #endif
 485 
 486 #if (ULTRASTOR_DEBUG & UD_RESET)
 487     printk("US14F: reset: returning\n");
 488 #endif
 489     return 0;
 490 }
 491 
 492 int ultrastor_biosparam(int size, int dev, int *info)
     /* [previous][next][first][last][top][bottom][index][help] */
 493 {
 494     unsigned int s = config.heads * config.sectors;
 495 
 496     info[0] = config.heads;
 497     info[1] = config.sectors;
 498     info[2] = (size + (s - 1)) / s;
 499     if (info[2] > 1024)
 500         info[2] = 1024;
 501     return 0;
 502 }
 503 
 504 static void ultrastor_interrupt(int cpl)
     /* [previous][next][first][last][top][bottom][index][help] */
 505 {
 506 #if (ULTRASTOR_DEBUG & UD_INTERRUPT)
 507     printk("US14F: interrupt: called: status = %08X\n",
 508            (mscp.adapter_status << 16) | mscp.target_status);
 509 #endif
 510 
 511     if (ultrastor_done == 0)
 512         panic("US14F: interrupt: unexpected interrupt");
 513     else {
 514         void (*done)(Scsi_Cmnd *);
 515         Scsi_Cmnd *SCtmp;
 516 
 517         /* Save ultrastor_done locally and zero before calling.  This is needed
 518            as once we call done, we may get another command queued before this
 519            interrupt service routine can return. */
 520         done = ultrastor_done;
 521         ultrastor_done = 0;
 522         SCtmp = SCint;
 523 
 524         /* Clean ICM slot (set ICMINT bit to 0) */
 525         outb_p(0x1, SYS_DOORBELL_INTR(PORT_ADDRESS));
 526 
 527         /* Let the higher levels know that we're done */
 528         /* ??? status is wrong here... */
 529         SCtmp->result = (mscp.adapter_status << 16) | mscp.target_status;
 530 
 531         /* Free temp space used for scatter-gather list */
 532         if (SCtmp->host_scribble)
 533                 scsi_free(SCtmp->host_scribble, 512);
 534 
 535         /* Free up mscp block for next command */
 536         mscp_free = TRUE;
 537 
 538         done(SCtmp);
 539     }
 540 
 541 #if (ULTRASTOR_DEBUG & UD_INTERRUPT)
 542     printk("US14F: interrupt: returning\n");
 543 #endif
 544 }

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