Annotation of linux/kernel/blk_drv/scsi/ultrastor.c, revision 1.1.1.2

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.