root/kernel/blk_drv/scsi/ultrastor.c

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

DEFINITIONS

This source file includes following definitions.
  1. ultrastor_14f_detect
  2. ultrastor_14f_info
  3. ultrastor_14f_queuecommand
  4. ultrastor_14f_command
  5. ultrastor_14f_abort
  6. ultrastor_14f_reset
  7. 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  *      Thanks to UltraStor for providing the necessary documentation
   7  */
   8 
   9 /*
  10  * NOTES:
  11  *    The UltraStor 14F is an intelligent, high performance ISA SCSI-2 host
  12  *    adapter.  It is essentially an ISA version of the UltraStor 24F EISA
  13  *    adapter.  It supports first-party DMA, command queueing, and
  14  *    scatter/gather I/O.  It can also emulate the standard AT MFM/RLL/IDE
  15  *    interface for use with OS's which don't support SCSI.
  16  *
  17  *    This driver may also work (with some small changes) with the UltraStor
  18  *    24F.  I have no way of confirming this...
  19  *
  20  *    Places flagged with a triple question-mark are things which are either
  21  *    unfinished, questionable, or wrong.
  22  */
  23 
  24 /*
  25  * CAVEATS: ???
  26  *    This driver is VERY stupid.  It takes no advantage of much of the power
  27  *    of the UltraStor controller.  I hope to go back and beat it into shape,
  28  *    but PLEASE, anyone else who would like to, please make improvements!
  29  *
  30  *    By defining NO_QUEUEING in ultrastor.h, you disable the queueing feature
  31  *    of the mid-level SCSI driver.  Once I'm satisfied that the queueing
  32  *    version is as stable as the non-queueing version, I'll eliminate this
  33  *    option.
  34  */
  35 
  36 #include <linux/config.h>
  37 
  38 #ifdef CONFIG_SCSI_ULTRASTOR
  39 
  40 #include <linux/stddef.h>
  41 #include <linux/string.h>
  42 #include <linux/sched.h>
  43 #include <linux/kernel.h>
  44 
  45 #include <asm/io.h>
  46 #include <asm/system.h>
  47 
  48 #define ULTRASTOR_PRIVATE       /* Get the private stuff from ultrastor.h */
  49 #include "ultrastor.h"
  50 #include "scsi.h"
  51 #include "hosts.h"
  52 
  53 #define VERSION "1.0 beta"
  54 
  55 #define ARRAY_SIZE(arr) (sizeof (arr) / sizeof (arr)[0])
  56 #define BIT(n) (1ul << (n))
  57 #define BYTE(num, n) ((unsigned char)((unsigned int)(num) >> ((n) * 8)))
  58 
  59 /* Simply using "unsigned long" in these structures won't work as it causes
  60    alignment.  Perhaps the "aligned" attribute may be used in GCC 2.0 to get
  61    around this, but for now I use this hack. */
  62 typedef struct {
  63     unsigned char bytes[4];
  64 } Longword;
  65 
  66 /* Used to fetch the configuration info from the config i/o registers.  We
  67    then store (in a friendlier format) in config. */
  68 struct config_1 {
  69     unsigned char bios_segment: 3;
  70     unsigned char reserved: 1;
  71     unsigned char interrupt: 2;
  72     unsigned char dma_channel: 2;
  73 };
  74 struct config_2 {
  75     unsigned char ha_scsi_id: 3;
  76     unsigned char mapping_mode: 2;
  77     unsigned char bios_drive_number: 1;
  78     unsigned char tfr_port: 2;
  79 };
  80 
  81 /* Used to store configuration info read from config i/o registers.  Most of
  82    this is not used yet, but might as well save it. */
  83 struct config {
  84     unsigned short port_address;
  85     const void *bios_segment;
  86     unsigned char interrupt: 4;
  87     unsigned char dma_channel: 3;
  88     unsigned char ha_scsi_id: 3;
  89     unsigned char heads: 6;
  90     unsigned char sectors: 6;
  91     unsigned char bios_drive_number: 1;
  92 };
  93 
  94 /* MailBox SCSI Command Packet.  Basic command structure for communicating
  95    with controller. */
  96 struct mscp {
  97     unsigned char opcode: 3;            /* type of command */
  98     unsigned char xdir: 2;              /* data transfer direction */
  99     unsigned char dcn: 1;               /* disable disconnect */
 100     unsigned char ca: 1;                /* use cache (if available) */
 101     unsigned char sg: 1;                /* scatter/gather operation */
 102     unsigned char target_id: 3;         /* target SCSI id */
 103     unsigned char ch_no: 2;             /* SCSI channel (always 0 for 14f) */
 104     unsigned char lun: 3;               /* logical unit number */
 105     Longword transfer_data;             /* transfer data pointer */
 106     Longword transfer_data_length;      /* length in bytes */
 107     Longword command_link;              /* for linking command chains */
 108     unsigned char scsi_command_link_id; /* identifies command in chain */
 109     unsigned char number_of_sg_list;    /* (if sg is set) 8 bytes per list */
 110     unsigned char length_of_sense_byte;
 111     unsigned char length_of_scsi_cdbs;  /* 6, 10, or 12 */
 112     unsigned char scsi_cdbs[12];        /* SCSI commands */
 113     unsigned char adapter_status;       /* non-zero indicates HA error */
 114     unsigned char target_status;        /* non-zero indicates target error */
 115     Longword sense_data;
 116 };
 117 
 118 /* Allowed BIOS base addresses for 14f (NULL indicates reserved) */
 119 static const void *const bios_segment_table[8] = {
 120     NULL,            (void *)0xC4000, (void *)0xC8000, (void *)0xCC000,
 121     (void *)0xD0000, (void *)0xD4000, (void *)0xD8000, (void *)0xDC000,
 122 };
 123 
 124 /* Allowed IRQs for 14f */
 125 static const unsigned char interrupt_table[4] = { 15, 14, 11, 10 };
 126 
 127 /* Allowed DMA channels for 14f (0 indicates reserved) */
 128 static const unsigned char dma_channel_table[4] = { 5, 6, 7, 0 };
 129 
 130 /* Head/sector mappings allowed by 14f */
 131 static const struct {
 132     unsigned char heads;
 133     unsigned char sectors;
 134 } mapping_table[4] = { { 16, 63 }, { 64, 32 }, { 64, 63 }, { 0, 0 } };
 135 
 136 /* Config info */
 137 static struct config config;
 138 
 139 /* Our index in the host adapter array maintained by higher-level driver */
 140 static int host_number;
 141 
 142 /* PORT_ADDRESS is first port address used for i/o of messages. */
 143 #ifdef PORT_OVERRIDE
 144 # define PORT_ADDRESS PORT_OVERRIDE
 145 #else
 146 # define PORT_ADDRESS (config.port_address)
 147 #endif
 148 
 149 static volatile int aborted = 0;
 150 
 151 #ifndef PORT_OVERRIDE
 152 static const unsigned short ultrastor_ports[] = {
 153     0x330, 0x340, 0x310, 0x230, 0x240, 0x210, 0x130, 0x140,
 154 };
 155 #endif
 156 
 157 static void ultrastor_interrupt(int cpl);
 158 
 159 static void (*ultrastor_done)(int, int) = 0;
 160 
 161 static const struct {
 162     const char *signature;
 163     size_t offset;
 164     size_t length;
 165 } signatures[] = {
 166     { "SBIOS 1.01 COPYRIGHT (C) UltraStor Corporation,1990-1992.", 0x10, 57 },
 167 };
 168 
 169 int ultrastor_14f_detect(int hostnum)
     /* [previous][next][first][last][top][bottom][index][help] */
 170 {
 171     size_t i;
 172     unsigned char in_byte;
 173     struct config_1 config_1;
 174     struct config_2 config_2;
 175 
 176 #if (ULTRASTOR_DEBUG & UD_DETECT)
 177     printk("US14F: detect: called\n");
 178 #endif
 179 
 180 #ifndef PORT_OVERRIDE
 181     PORT_ADDRESS = 0;
 182     for (i = 0; i < ARRAY_SIZE(ultrastor_ports); i++) {
 183         PORT_ADDRESS = ultrastor_ports[i];
 184 #endif
 185 
 186 #if (ULTRASTOR_DEBUG & UD_DETECT)
 187         printk("US14F: detect: testing port address %03X\n", PORT_ADDRESS);
 188 #endif
 189 
 190         in_byte = inb(PRODUCT_ID(PORT_ADDRESS + 0));
 191         if (in_byte != US14F_PRODUCT_ID_0) {
 192 #if (ULTRASTOR_DEBUG & UD_DETECT)
 193 # ifdef PORT_OVERRIDE
 194             printk("US14F: detect: wrong product ID 0 - %02X\n", in_byte);
 195 # else
 196             printk("US14F: detect: no adapter at port %03X\n", PORT_ADDRESS);
 197 # endif
 198 #endif
 199 #ifdef PORT_OVERRIDE
 200             return FALSE;
 201 #else
 202             continue;
 203 #endif
 204         }
 205         in_byte = inb(PRODUCT_ID(PORT_ADDRESS + 1));
 206         /* Only upper nibble is defined for Product ID 1 */
 207         if ((in_byte & 0xF0) != US14F_PRODUCT_ID_1) {
 208 #if (ULTRASTOR_DEBUG & UD_DETECT)
 209 # ifdef PORT_OVERRIDE
 210             printk("US14F: detect: wrong product ID 1 - %02X\n", in_byte);
 211 # else
 212             printk("US14F: detect: no adapter at port %03X\n", PORT_ADDRESS);
 213 # endif
 214 #endif
 215 #ifdef PORT_OVERRIDE
 216             return FALSE;
 217 #else
 218             continue;
 219 #endif
 220         }
 221 #ifndef PORT_OVERRIDE
 222         break;
 223     }
 224     if (i == ARRAY_SIZE(ultrastor_ports)) {
 225 # if (ULTRASTOR_DEBUG & UD_DETECT)
 226         printk("US14F: detect: no port address found!\n");
 227 # endif
 228         return FALSE;
 229     }
 230 #endif
 231 
 232 #if (ULTRASTOR_DEBUG & UD_DETECT)
 233     printk("US14F: detect: adapter found at port address %03X\n",
 234            PORT_ADDRESS);
 235 #endif
 236 
 237     /* All above tests passed, must be the right thing.  Get some useful
 238        info. */
 239     *(char *)&config_1 = inb(CONFIG(PORT_ADDRESS + 0));
 240     *(char *)&config_2 = inb(CONFIG(PORT_ADDRESS + 1));
 241     config.bios_segment = bios_segment_table[config_1.bios_segment];
 242     config.interrupt = interrupt_table[config_1.interrupt];
 243     config.dma_channel = dma_channel_table[config_1.dma_channel];
 244     config.ha_scsi_id = config_2.ha_scsi_id;
 245     config.heads = mapping_table[config_2.mapping_mode].heads;
 246     config.sectors = mapping_table[config_2.mapping_mode].sectors;
 247     config.bios_drive_number = config_2.bios_drive_number;
 248 
 249     /* To verify this card, we simply look for the UltraStor SCSI from the
 250        BIOS version notice. */
 251     if (config.bios_segment != NULL) {
 252         int found = 0;
 253 
 254         for (i = 0; !found && i < ARRAY_SIZE(signatures); i++)
 255             if (memcmp((char *)config.bios_segment + signatures[i].offset,
 256                        signatures[i].signature, signatures[i].length))
 257                 found = 1;
 258         if (!found)
 259             config.bios_segment = NULL;
 260     }
 261     if (!config.bios_segment) {
 262 #if (ULTRASTOR_DEBUG & UD_DETECT)
 263         printk("US14F: detect: not detected.\n");
 264 #endif
 265         return FALSE;
 266     }
 267 
 268     /* Final consistancy check, verify previous info. */
 269     if (!config.dma_channel || !(config_2.tfr_port & 0x2)) {
 270 #if (ULTRASTOR_DEBUG & UD_DETECT)
 271         printk("US14F: detect: consistancy check failed\n");
 272 #endif
 273         return FALSE;
 274     }
 275 
 276     /* If we were TRULY paranoid, we could issue a host adapter inquiry
 277        command here and verify the data returned.  But frankly, I'm
 278        exhausted! */
 279 
 280     /* Finally!  Now I'm satisfied... */
 281 #if (ULTRASTOR_DEBUG & UD_DETECT)
 282     printk("US14F: detect: detect succeeded\n"
 283            "  Port address: %03X\n"
 284            "  BIOS segment: %05X\n"
 285            "  Interrupt: %u\n"
 286            "  DMA channel: %u\n"
 287            "  H/A SCSI ID: %u\n",
 288            PORT_ADDRESS, config.bios_segment, config.interrupt,
 289            config.dma_channel, config.ha_scsi_id);
 290 #endif
 291     host_number = hostnum;
 292     scsi_hosts[hostnum].this_id = config.ha_scsi_id;
 293 #ifndef NO_QUEUEING
 294     {
 295         struct sigaction sa;
 296 
 297         sa.sa_handler = ultrastor_interrupt;
 298         sa.sa_mask = 0;
 299         sa.sa_flags = SA_INTERRUPT;     /* ??? Do we really need this? */
 300         sa.sa_restorer = 0;
 301         if (irqaction(config.interrupt, &sa)) {
 302             printk("Unable to get IRQ%u for UltraStor controller\n",
 303                    config.interrupt);
 304             return FALSE;
 305         }
 306     }
 307 #endif
 308     return TRUE;
 309 }
 310 
 311 const char *ultrastor_14f_info(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 312 {
 313     return "UltraStor 14F SCSI driver version "
 314            VERSION
 315            " by David B. Gentzel\n";
 316 }
 317 
 318 static struct mscp mscp = {
 319     OP_SCSI, DTD_SCSI, 0, 1, 0          /* This stuff doesn't change */
 320 };
 321 
 322 int ultrastor_14f_queuecommand(unsigned char target, const void *cmnd,
     /* [previous][next][first][last][top][bottom][index][help] */
 323                                void *buff, int bufflen, void (*done)(int, int))
 324 {
 325     unsigned char in_byte;
 326 
 327 #if (ULTRASTOR_DEBUG & UD_COMMAND)
 328     printk("US14F: queuecommand: called\n");
 329 #endif
 330 
 331     /* Skip first (constant) byte */
 332     memset((char *)&mscp + 1, 0, sizeof (struct mscp) - 1);
 333     mscp.target_id = target;
 334     /* mscp.lun = ???; */
 335     mscp.transfer_data = *(Longword *)&buff;
 336     mscp.transfer_data_length = *(Longword *)&bufflen,
 337     mscp.length_of_scsi_cdbs = ((*(unsigned char *)cmnd <= 0x1F) ? 6 : 10);
 338     memcpy(mscp.scsi_cdbs, cmnd, mscp.length_of_scsi_cdbs);
 339 
 340     /* Find free OGM slot (OGMINT bit is 0) */
 341     do
 342         in_byte = inb_p(LCL_DOORBELL_INTR(PORT_ADDRESS));
 343     while (!aborted && (in_byte & 1));
 344     if (aborted) {
 345 #if (ULTRASTOR_DEBUG & (UD_COMMAND | UD_ABORT))
 346         printk("US14F: queuecommand: aborted\n");
 347 #endif
 348         /* ??? is this right? */
 349         return (aborted << 16);
 350     }
 351 
 352     /* Store pointer in OGM address bytes */
 353     outb_p(BYTE(&mscp, 0), OGM_DATA_PTR(PORT_ADDRESS + 0));
 354     outb_p(BYTE(&mscp, 1), OGM_DATA_PTR(PORT_ADDRESS + 1));
 355     outb_p(BYTE(&mscp, 2), OGM_DATA_PTR(PORT_ADDRESS + 2));
 356     outb_p(BYTE(&mscp, 3), OGM_DATA_PTR(PORT_ADDRESS + 3));
 357 
 358     /* Issue OGM interrupt */
 359     outb_p(0x1, LCL_DOORBELL_INTR(PORT_ADDRESS));
 360 
 361     ultrastor_done = done;
 362 
 363 #if (ULTRASTOR_DEBUG & UD_COMMAND)
 364     printk("US14F: queuecommand: returning\n");
 365 #endif
 366 
 367     return 0;
 368 }
 369 
 370 #ifdef NO_QUEUEING
 371 int ultrastor_14f_command(unsigned char target, const void *cmnd,
     /* [previous][next][first][last][top][bottom][index][help] */
 372                           void *buff, int bufflen)
 373 {
 374     unsigned char in_byte;
 375 
 376 #if (ULTRASTOR_DEBUG & UD_COMMAND)
 377     printk("US14F: command: called\n");
 378 #endif
 379 
 380     (void)ultrastor_14f_queuecommand(target, cmnd, buff, bufflen, 0);
 381 
 382     /* Wait for ICM interrupt */
 383     do
 384         in_byte = inb_p(SYS_DOORBELL_INTR(PORT_ADDRESS));
 385     while (!aborted && !(in_byte & 1));
 386     if (aborted) {
 387 #if (ULTRASTOR_DEBUG & (UD_COMMAND | UD_ABORT))
 388         printk("US14F: command: aborted\n");
 389 #endif
 390         /* ??? is this right? */
 391         return (aborted << 16);
 392     }
 393 
 394     /* Clean ICM slot (set ICMINT bit to 0) */
 395     outb_p(0x1, SYS_DOORBELL_INTR(PORT_ADDRESS));
 396 
 397 #if (ULTRASTOR_DEBUG & UD_COMMAND)
 398     printk("US14F: command: returning %08X\n",
 399            (mscp.adapter_status << 16) | mscp.target_status);
 400 #endif
 401 
 402     /* ??? not right, but okay for now? */
 403     return (mscp.adapter_status << 16) | mscp.target_status;
 404 }
 405 #endif
 406 
 407 int ultrastor_14f_abort(int code)
     /* [previous][next][first][last][top][bottom][index][help] */
 408 {
 409 #if (ULTRASTOR_DEBUG & UD_ABORT)
 410     printk("US14F: abort: called\n");
 411 #endif
 412 
 413     aborted = (code ? code : DID_ABORT);
 414 
 415 #if (ULTRASTOR_DEBUG & UD_ABORT)
 416     printk("US14F: abort: returning\n");
 417 #endif
 418 
 419     return 0;
 420 }
 421 
 422 int ultrastor_14f_reset(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 423 {
 424     unsigned char in_byte;
 425 
 426 #if (ULTRASTOR_DEBUG & UD_RESET)
 427     printk("US14F: reset: called\n");
 428 #endif
 429 
 430     /* Issue SCSI BUS reset */
 431     outb_p(0x20, LCL_DOORBELL_INTR(PORT_ADDRESS));
 432 
 433     /* Wait for completion... */
 434     do
 435         in_byte = inb_p(LCL_DOORBELL_INTR(PORT_ADDRESS));
 436     while (in_byte & 0x20);
 437 
 438     aborted = DID_RESET;
 439 
 440 #if (ULTRASTOR_DEBUG & UD_RESET)
 441     printk("US14F: reset: returning\n");
 442 #endif
 443     return 0;
 444 }
 445 
 446 #ifndef NO_QUEUEING
 447 static void ultrastor_interrupt(int cpl)
     /* [previous][next][first][last][top][bottom][index][help] */
 448 {
 449 #if (ULTRASTOR_DEBUG & UD_INTERRUPT)
 450     printk("US14F: interrupt: called: status = %08X\n",
 451            (mscp.adapter_status << 16) | mscp.target_status);
 452 #endif
 453 
 454     if (ultrastor_done == 0)
 455         panic("US14F: interrupt: unexpected interrupt!\n");
 456     else {
 457         void (*done)(int, int);
 458 
 459         /* Save ultrastor_done locally and zero before calling.  This is needed
 460            as once we call done, we may get another command queued before this
 461            interrupt service routine can return. */
 462         done = ultrastor_done;
 463         ultrastor_done = 0;
 464 
 465         /* Clean ICM slot (set ICMINT bit to 0) */
 466         outb_p(0x1, SYS_DOORBELL_INTR(PORT_ADDRESS));
 467 
 468         /* Let the higher levels know that we're done */
 469         /* ??? status is wrong here... */
 470         done(host_number, (mscp.adapter_status << 16) | mscp.target_status);
 471     }
 472 
 473 #if (ULTRASTOR_DEBUG & UD_INTERRUPT)
 474     printk("US14F: interrupt: returning\n");
 475 #endif
 476 }
 477 #endif
 478 
 479 #endif

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