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

1.1       root        1: /*
1.1.1.4 ! root        2:  *     ultrastor.c     Copyright (C) 1992 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
1.1.1.4 ! root       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!
1.1.1.2   root       29:  *
1.1.1.3   root       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.
1.1.1.2   root       34:  */
1.1       root       35: 
                     36: #include <linux/config.h>
                     37: 
                     38: #ifdef CONFIG_SCSI_ULTRASTOR
                     39: 
1.1.1.3   root       40: #include <linux/stddef.h>
1.1       root       41: #include <linux/string.h>
                     42: #include <linux/sched.h>
                     43: #include <linux/kernel.h>
1.1.1.3   root       44: 
1.1       root       45: #include <asm/io.h>
1.1.1.2   root       46: #include <asm/system.h>
1.1       root       47: 
1.1.1.2   root       48: #define ULTRASTOR_PRIVATE      /* Get the private stuff from ultrastor.h */
1.1       root       49: #include "ultrastor.h"
                     50: #include "scsi.h"
                     51: #include "hosts.h"
                     52: 
1.1.1.2   root       53: #define VERSION "1.0 beta"
1.1       root       54: 
                     55: #define ARRAY_SIZE(arr) (sizeof (arr) / sizeof (arr)[0])
1.1.1.2   root       56: #define BIT(n) (1ul << (n))
1.1       root       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: 
1.1.1.2   root       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: 
1.1       root       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 {
1.1.1.2   root       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;
1.1       root       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: 
1.1.1.2   root      130: /* Head/sector mappings allowed by 14f */
1.1       root      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
1.1.1.2   root      146: # define PORT_ADDRESS (config.port_address)
1.1       root      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: 
1.1.1.4 ! root      157: static void ultrastor_interrupt(int cpl);
1.1.1.2   root      158: 
                    159: static void (*ultrastor_done)(int, int) = 0;
                    160: 
1.1       root      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)
                    170: {
                    171:     size_t i;
                    172:     unsigned char in_byte;
1.1.1.2   root      173:     struct config_1 config_1;
                    174:     struct config_2 config_2;
1.1       root      175: 
1.1.1.2   root      176: #if (ULTRASTOR_DEBUG & UD_DETECT)
                    177:     printk("US14F: detect: called\n");
1.1       root      178: #endif
                    179: 
                    180: #ifndef PORT_OVERRIDE
1.1.1.2   root      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
1.1.1.3   root      196:            printk("US14F: detect: no adapter at port %03X\n", PORT_ADDRESS);
1.1.1.2   root      197: # endif
1.1       root      198: #endif
1.1.1.2   root      199: #ifdef PORT_OVERRIDE
                    200:            return FALSE;
                    201: #else
                    202:            continue;
1.1       root      203: #endif
1.1.1.2   root      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
1.1.1.3   root      212:            printk("US14F: detect: no adapter at port %03X\n", PORT_ADDRESS);
1.1.1.2   root      213: # endif
1.1       root      214: #endif
1.1.1.2   root      215: #ifdef PORT_OVERRIDE
                    216:            return FALSE;
                    217: #else
                    218:            continue;
1.1       root      219: #endif
1.1.1.2   root      220:        }
                    221: #ifndef PORT_OVERRIDE
                    222:        break;
1.1       root      223:     }
1.1.1.2   root      224:     if (i == ARRAY_SIZE(ultrastor_ports)) {
                    225: # if (ULTRASTOR_DEBUG & UD_DETECT)
                    226:        printk("US14F: detect: no port address found!\n");
                    227: # endif
1.1       root      228:        return FALSE;
                    229:     }
1.1.1.2   root      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
1.1       root      236: 
                    237:     /* All above tests passed, must be the right thing.  Get some useful
                    238:        info. */
1.1.1.2   root      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;
1.1       root      248: 
                    249:     /* To verify this card, we simply look for the UltraStor SCSI from the
                    250:        BIOS version notice. */
1.1.1.2   root      251:     if (config.bios_segment != NULL) {
1.1       root      252:        int found = 0;
                    253: 
                    254:        for (i = 0; !found && i < ARRAY_SIZE(signatures); i++)
1.1.1.2   root      255:            if (memcmp((char *)config.bios_segment + signatures[i].offset,
1.1       root      256:                       signatures[i].signature, signatures[i].length))
                    257:                found = 1;
                    258:        if (!found)
1.1.1.2   root      259:            config.bios_segment = NULL;
1.1       root      260:     }
1.1.1.2   root      261:     if (!config.bios_segment) {
                    262: #if (ULTRASTOR_DEBUG & UD_DETECT)
                    263:        printk("US14F: detect: not detected.\n");
1.1       root      264: #endif
                    265:        return FALSE;
                    266:     }
                    267: 
                    268:     /* Final consistancy check, verify previous info. */
1.1.1.2   root      269:     if (!config.dma_channel || !(config_2.tfr_port & 0x2)) {
                    270: #if (ULTRASTOR_DEBUG & UD_DETECT)
                    271:        printk("US14F: detect: consistancy check failed\n");
1.1       root      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... */
1.1.1.2   root      281: #if (ULTRASTOR_DEBUG & UD_DETECT)
                    282:     printk("US14F: detect: detect succeeded\n"
                    283:           "  Port address: %03X\n"
1.1       root      284:           "  BIOS segment: %05X\n"
1.1.1.2   root      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);
1.1       root      290: #endif
                    291:     host_number = hostnum;
1.1.1.2   root      292:     scsi_hosts[hostnum].this_id = config.ha_scsi_id;
1.1.1.3   root      293: #ifndef NO_QUEUEING
1.1.1.4 ! root      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:     }
1.1.1.2   root      307: #endif
1.1       root      308:     return TRUE;
                    309: }
                    310: 
                    311: const char *ultrastor_14f_info(void)
                    312: {
                    313:     return "UltraStor 14F SCSI driver version "
                    314:           VERSION
                    315:           " by David B. Gentzel\n";
                    316: }
                    317: 
1.1.1.2   root      318: static struct mscp mscp = {
1.1.1.4 ! root      319:     OP_SCSI, DTD_SCSI, 0, 1, 0         /* This stuff doesn't change */
1.1.1.2   root      320: };
                    321: 
1.1       root      322: int ultrastor_14f_queuecommand(unsigned char target, const void *cmnd,
                    323:                               void *buff, int bufflen, void (*done)(int, int))
                    324: {
                    325:     unsigned char in_byte;
                    326: 
1.1.1.2   root      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);
1.1       root      338:     memcpy(mscp.scsi_cdbs, cmnd, mscp.length_of_scsi_cdbs);
                    339: 
                    340:     /* Find free OGM slot (OGMINT bit is 0) */
                    341:     do
1.1.1.2   root      342:        in_byte = inb_p(LCL_DOORBELL_INTR(PORT_ADDRESS));
1.1       root      343:     while (!aborted && (in_byte & 1));
1.1.1.3   root      344:     if (aborted) {
                    345: #if (ULTRASTOR_DEBUG & (UD_COMMAND | UD_ABORT))
                    346:        printk("US14F: queuecommand: aborted\n");
                    347: #endif
1.1       root      348:        /* ??? is this right? */
                    349:        return (aborted << 16);
1.1.1.3   root      350:     }
1.1       root      351: 
                    352:     /* Store pointer in OGM address bytes */
1.1.1.2   root      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));
1.1       root      357: 
                    358:     /* Issue OGM interrupt */
1.1.1.2   root      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: 
1.1.1.3   root      370: #ifdef NO_QUEUEING
1.1.1.2   root      371: int ultrastor_14f_command(unsigned char target, const void *cmnd,
                    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);
1.1       root      381: 
                    382:     /* Wait for ICM interrupt */
                    383:     do
1.1.1.2   root      384:        in_byte = inb_p(SYS_DOORBELL_INTR(PORT_ADDRESS));
1.1       root      385:     while (!aborted && !(in_byte & 1));
1.1.1.3   root      386:     if (aborted) {
                    387: #if (ULTRASTOR_DEBUG & (UD_COMMAND | UD_ABORT))
                    388:        printk("US14F: command: aborted\n");
                    389: #endif
1.1       root      390:        /* ??? is this right? */
                    391:        return (aborted << 16);
1.1.1.3   root      392:     }
1.1       root      393: 
                    394:     /* Clean ICM slot (set ICMINT bit to 0) */
1.1.1.2   root      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
1.1       root      401: 
                    402:     /* ??? not right, but okay for now? */
                    403:     return (mscp.adapter_status << 16) | mscp.target_status;
                    404: }
1.1.1.2   root      405: #endif
1.1       root      406: 
                    407: int ultrastor_14f_abort(int code)
                    408: {
1.1.1.3   root      409: #if (ULTRASTOR_DEBUG & UD_ABORT)
                    410:     printk("US14F: abort: called\n");
                    411: #endif
                    412: 
1.1       root      413:     aborted = (code ? code : DID_ABORT);
1.1.1.3   root      414: 
                    415: #if (ULTRASTOR_DEBUG & UD_ABORT)
                    416:     printk("US14F: abort: returning\n");
                    417: #endif
                    418: 
1.1       root      419:     return 0;
                    420: }
                    421: 
                    422: int ultrastor_14f_reset(void)
                    423: {
                    424:     unsigned char in_byte;
                    425: 
1.1.1.2   root      426: #if (ULTRASTOR_DEBUG & UD_RESET)
                    427:     printk("US14F: reset: called\n");
1.1       root      428: #endif
                    429: 
                    430:     /* Issue SCSI BUS reset */
1.1.1.2   root      431:     outb_p(0x20, LCL_DOORBELL_INTR(PORT_ADDRESS));
                    432: 
1.1       root      433:     /* Wait for completion... */
                    434:     do
1.1.1.2   root      435:        in_byte = inb_p(LCL_DOORBELL_INTR(PORT_ADDRESS));
1.1       root      436:     while (in_byte & 0x20);
                    437: 
                    438:     aborted = DID_RESET;
                    439: 
1.1.1.2   root      440: #if (ULTRASTOR_DEBUG & UD_RESET)
                    441:     printk("US14F: reset: returning\n");
1.1       root      442: #endif
                    443:     return 0;
                    444: }
                    445: 
1.1.1.3   root      446: #ifndef NO_QUEUEING
1.1.1.4 ! root      447: static void ultrastor_interrupt(int cpl)
1.1.1.2   root      448: {
1.1.1.3   root      449: #if (ULTRASTOR_DEBUG & UD_INTERRUPT)
1.1.1.4 ! root      450:     printk("US14F: interrupt: called: status = %08X\n",
1.1.1.2   root      451:           (mscp.adapter_status << 16) | mscp.target_status);
1.1.1.3   root      452: #endif
                    453: 
                    454:     if (ultrastor_done == 0)
1.1.1.4 ! root      455:        panic("US14F: interrupt: unexpected interrupt!\n");
1.1.1.3   root      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)
1.1.1.4 ! root      474:     printk("US14F: interrupt: returning\n");
1.1.1.3   root      475: #endif
1.1.1.2   root      476: }
                    477: #endif
                    478: 
1.1       root      479: #endif

unix.superglobalmegacorp.com

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