|
|
1.1 ! root 1: /* ! 2: * ultrastor.c (C) 1991 David B. Gentzel ! 3: * Low-level scsi driver for UltraStor 14F ! 4: * by David B. Gentzel, Whitfield Software Services, Carnegie, PA ! 5: * ([email protected]) ! 6: * Thanks to UltraStor for providing the necessary documentation ! 7: */ ! 8: ! 9: /* ??? Caveats: ! 10: This driver is VERY stupid. It takes no advantage of much of the power of ! 11: the UltraStor controller. We just sit-and-spin while waiting for commands ! 12: to complete. I hope to go back and beat it into shape, but PLEASE, anyone ! 13: else who would like to, please make improvements! */ ! 14: ! 15: #include <linux/config.h> ! 16: ! 17: #ifdef CONFIG_SCSI_ULTRASTOR ! 18: ! 19: #include <stddef.h> ! 20: ! 21: #include <linux/string.h> ! 22: #include <linux/config.h> ! 23: #include <linux/sched.h> ! 24: #include <linux/fs.h> ! 25: #include <linux/kernel.h> ! 26: #include <linux/hdreg.h> ! 27: #include <asm/system.h> ! 28: #include <asm/io.h> ! 29: #include <asm/segment.h> ! 30: ! 31: #include "ultrastor.h" ! 32: #include "scsi.h" ! 33: #include "hosts.h" ! 34: ! 35: #define VERSION "1.0 alpha" ! 36: ! 37: #define ARRAY_SIZE(arr) (sizeof (arr) / sizeof (arr)[0]) ! 38: #define BYTE(num, n) ((unsigned char)((unsigned int)(num) >> ((n) * 8))) ! 39: ! 40: /* Simply using "unsigned long" in these structures won't work as it causes ! 41: alignment. Perhaps the "aligned" attribute may be used in GCC 2.0 to get ! 42: around this, but for now I use this hack. */ ! 43: typedef struct { ! 44: unsigned char bytes[4]; ! 45: } Longword; ! 46: ! 47: /* Used to store configuration info read from config i/o registers. Most of ! 48: this is not used yet, but might as well save it. */ ! 49: struct config { ! 50: struct { ! 51: unsigned char bios_segment: 3; ! 52: unsigned char reserved: 1; ! 53: unsigned char interrupt: 2; ! 54: unsigned char dma_channel: 2; ! 55: } config_1; ! 56: struct { ! 57: unsigned char ha_scsi_id: 3; ! 58: unsigned char mapping_mode: 2; ! 59: unsigned char bios_drive_number: 1; ! 60: unsigned char tfr_port: 2; ! 61: } config_2; ! 62: }; ! 63: ! 64: /* MailBox SCSI Command Packet. Basic command structure for communicating ! 65: with controller. */ ! 66: struct mscp { ! 67: unsigned char opcode: 3; /* type of command */ ! 68: unsigned char xdir: 2; /* data transfer direction */ ! 69: unsigned char dcn: 1; /* disable disconnect */ ! 70: unsigned char ca: 1; /* use cache (if available) */ ! 71: unsigned char sg: 1; /* scatter/gather operation */ ! 72: unsigned char target_id: 3; /* target SCSI id */ ! 73: unsigned char ch_no: 2; /* SCSI channel (always 0 for 14f) */ ! 74: unsigned char lun: 3; /* logical unit number */ ! 75: Longword transfer_data; /* transfer data pointer */ ! 76: Longword transfer_data_length; /* length in bytes */ ! 77: Longword command_link; /* for linking command chains */ ! 78: unsigned char scsi_command_link_id; /* identifies command in chain */ ! 79: unsigned char number_of_sg_list; /* (if sg is set) 8 bytes per list */ ! 80: unsigned char length_of_sense_byte; ! 81: unsigned char length_of_scsi_cdbs; /* 6, 10, or 12 */ ! 82: unsigned char scsi_cdbs[12]; /* SCSI commands */ ! 83: unsigned char adapter_status; /* non-zero indicates HA error */ ! 84: unsigned char target_status; /* non-zero indicates target error */ ! 85: Longword sense_data; ! 86: }; ! 87: ! 88: /* Allowed BIOS base addresses for 14f (NULL indicates reserved) */ ! 89: static const void *const bios_segment_table[8] = { ! 90: NULL, (void *)0xC4000, (void *)0xC8000, (void *)0xCC000, ! 91: (void *)0xD0000, (void *)0xD4000, (void *)0xD8000, (void *)0xDC000, ! 92: }; ! 93: ! 94: /* Allowed IRQs for 14f */ ! 95: static const unsigned char interrupt_table[4] = { 15, 14, 11, 10 }; ! 96: ! 97: /* Allowed DMA channels for 14f (0 indicates reserved) */ ! 98: static const unsigned char dma_channel_table[4] = { 5, 6, 7, 0 }; ! 99: ! 100: #if 0 /* Not currently used, head/sector mappings allowed by 14f */ ! 101: static const struct { ! 102: unsigned char heads; ! 103: unsigned char sectors; ! 104: } mapping_table[4] = { { 16, 63 }, { 64, 32 }, { 64, 63 }, { 0, 0 } }; ! 105: #endif ! 106: ! 107: /* Config info */ ! 108: static struct config config; ! 109: ! 110: /* Our index in the host adapter array maintained by higher-level driver */ ! 111: static int host_number; ! 112: ! 113: /* PORT_ADDRESS is first port address used for i/o of messages. */ ! 114: #ifdef PORT_OVERRIDE ! 115: # define PORT_ADDRESS PORT_OVERRIDE ! 116: #else ! 117: static unsigned short port_address = 0; ! 118: # define PORT_ADDRESS port_address ! 119: #endif ! 120: ! 121: static volatile int aborted = 0; ! 122: ! 123: #ifndef PORT_OVERRIDE ! 124: static const unsigned short ultrastor_ports[] = { ! 125: 0x330, 0x340, 0x310, 0x230, 0x240, 0x210, 0x130, 0x140, ! 126: }; ! 127: #endif ! 128: ! 129: static const struct { ! 130: const char *signature; ! 131: size_t offset; ! 132: size_t length; ! 133: } signatures[] = { ! 134: { "SBIOS 1.01 COPYRIGHT (C) UltraStor Corporation,1990-1992.", 0x10, 57 }, ! 135: }; ! 136: ! 137: int ultrastor_14f_detect(int hostnum) ! 138: { ! 139: size_t i; ! 140: unsigned char in_byte; ! 141: const void *base_address; ! 142: ! 143: #ifdef DEBUG ! 144: printk("ultrastor_14f_detect: called\n"); ! 145: #endif ! 146: ! 147: #ifndef PORT_OVERRIDE ! 148: /* ??? This is easy to implement, but I'm not sure how "friendly" it is to ! 149: go off and read random i/o ports. */ ! 150: # error Not implemented! ! 151: #endif ! 152: ! 153: if (!PORT_ADDRESS) { ! 154: #ifdef DEBUG ! 155: printk("ultrastor_14f_detect: no port address found!\n"); ! 156: #endif ! 157: return FALSE; ! 158: } ! 159: ! 160: #ifdef DEBUG ! 161: printk("ultrastor_14f_detect: port address = %X\n", PORT_ADDRESS); ! 162: #endif ! 163: ! 164: in_byte = inb(PRODUCT_ID(PORT_ADDRESS + 0)); ! 165: if (in_byte != US14F_PRODUCT_ID_0) { ! 166: #ifdef DEBUG ! 167: printk("ultrastor_14f_detect: unknown product ID 0 - %02X\n", in_byte); ! 168: #endif ! 169: return FALSE; ! 170: } ! 171: in_byte = inb(PRODUCT_ID(PORT_ADDRESS + 1)); ! 172: /* Only upper nibble is defined for Product ID 1 */ ! 173: if ((in_byte & 0xF0) != US14F_PRODUCT_ID_1) { ! 174: #ifdef DEBUG ! 175: printk("ultrastor_14f_detect: unknown product ID 1 - %02X\n", in_byte); ! 176: #endif ! 177: return FALSE; ! 178: } ! 179: ! 180: /* All above tests passed, must be the right thing. Get some useful ! 181: info. */ ! 182: *(char *)&config.config_1 = inb(CONFIG(PORT_ADDRESS + 0)); ! 183: *(char *)&config.config_2 = inb(CONFIG(PORT_ADDRESS + 1)); ! 184: ! 185: /* To verify this card, we simply look for the UltraStor SCSI from the ! 186: BIOS version notice. */ ! 187: base_address = bios_segment_table[config.config_1.bios_segment]; ! 188: if (base_address != NULL) { ! 189: int found = 0; ! 190: ! 191: for (i = 0; !found && i < ARRAY_SIZE(signatures); i++) ! 192: if (memcmp((char *)base_address + signatures[i].offset, ! 193: signatures[i].signature, signatures[i].length)) ! 194: found = 1; ! 195: if (!found) ! 196: base_address = NULL; ! 197: } ! 198: if (!base_address) { ! 199: #ifdef DEBUG ! 200: printk("ultrastor_14f_detect: not detected.\n"); ! 201: #endif ! 202: return FALSE; ! 203: } ! 204: ! 205: /* Final consistancy check, verify previous info. */ ! 206: if (!dma_channel_table[config.config_1.dma_channel] ! 207: || !(config.config_2.tfr_port & 0x2)) { ! 208: #ifdef DEBUG ! 209: printk("ultrastor_14f_detect: consistancy check failed\n"); ! 210: #endif ! 211: return FALSE; ! 212: } ! 213: ! 214: /* If we were TRULY paranoid, we could issue a host adapter inquiry ! 215: command here and verify the data returned. But frankly, I'm ! 216: exhausted! */ ! 217: ! 218: /* Finally! Now I'm satisfied... */ ! 219: #ifdef DEBUG ! 220: printk("ultrastor_14f_detect: detect succeeded\n" ! 221: " BIOS segment: %05X\n" ! 222: " Interrupt: %d\n" ! 223: " DMA channel: %d\n" ! 224: " H/A SCSI ID: %d\n", ! 225: base_address, interrupt_table[config.config_1.interrupt], ! 226: dma_channel_table[config.config_1.dma_channel], ! 227: config.config_2.ha_scsi_id); ! 228: #endif ! 229: host_number = hostnum; ! 230: scsi_hosts[hostnum].this_id = config.config_2.ha_scsi_id; ! 231: return TRUE; ! 232: } ! 233: ! 234: const char *ultrastor_14f_info(void) ! 235: { ! 236: return "UltraStor 14F SCSI driver version " ! 237: VERSION ! 238: " by David B. Gentzel\n"; ! 239: } ! 240: ! 241: #if 0 ! 242: int ultrastor_14f_queuecommand(unsigned char target, const void *cmnd, ! 243: void *buff, int bufflen, void (*done)(int, int)) ! 244: #else ! 245: int ultrastor_14f_command(unsigned char target, const void *cmnd, ! 246: void *buff, int bufflen) ! 247: #endif ! 248: { ! 249: struct mscp mscp = { ! 250: OP_SCSI, DTD_SCSI, FALSE, TRUE, FALSE, ! 251: target, 0, 0 /* LUN??? */, ! 252: *(Longword *)&buff, ! 253: *(Longword *)&bufflen, ! 254: { 0, 0, 0, 0 }, ! 255: 0, ! 256: 0, ! 257: 0, ! 258: ((*(char *)cmnd <= 0x1F) ? 6 : 10), ! 259: { 0 }, /* Filled in via memcpy below */ ! 260: 0, ! 261: 0, ! 262: { 0, 0, 0, 0 } ! 263: }; ! 264: unsigned char in_byte; ! 265: ! 266: memcpy(mscp.scsi_cdbs, cmnd, mscp.length_of_scsi_cdbs); ! 267: ! 268: /* Find free OGM slot (OGMINT bit is 0) */ ! 269: do ! 270: in_byte = inb(LCL_DOORBELL_INTR(PORT_ADDRESS)); ! 271: while (!aborted && (in_byte & 1)); ! 272: if (aborted) ! 273: /* ??? is this right? */ ! 274: return (aborted << 16); ! 275: ! 276: /* Store pointer in OGM address bytes */ ! 277: outb(BYTE(&mscp, 0), OGM_DATA_PTR(PORT_ADDRESS + 0)); ! 278: outb(BYTE(&mscp, 1), OGM_DATA_PTR(PORT_ADDRESS + 1)); ! 279: outb(BYTE(&mscp, 2), OGM_DATA_PTR(PORT_ADDRESS + 2)); ! 280: outb(BYTE(&mscp, 3), OGM_DATA_PTR(PORT_ADDRESS + 3)); ! 281: ! 282: /* Issue OGM interrupt */ ! 283: outb(0x1, LCL_DOORBELL_INTR(PORT_ADDRESS)); ! 284: ! 285: /* Wait for ICM interrupt */ ! 286: do ! 287: in_byte = inb(SYS_DOORBELL_INTR(PORT_ADDRESS)); ! 288: while (!aborted && !(in_byte & 1)); ! 289: if (aborted) ! 290: /* ??? is this right? */ ! 291: return (aborted << 16); ! 292: ! 293: /* Clean ICM slot (set ICMINT bit to 0) */ ! 294: outb(0x1, SYS_DOORBELL_INTR(PORT_ADDRESS)); ! 295: ! 296: /* ??? not right, but okay for now? */ ! 297: return (mscp.adapter_status << 16) | mscp.target_status; ! 298: } ! 299: ! 300: int ultrastor_14f_abort(int code) ! 301: { ! 302: aborted = (code ? code : DID_ABORT); ! 303: return 0; ! 304: } ! 305: ! 306: int ultrastor_14f_reset(void) ! 307: { ! 308: unsigned char in_byte; ! 309: ! 310: #ifdef DEBUG ! 311: printk("ultrastor_14f_reset: called\n"); ! 312: #endif ! 313: ! 314: /* Issue SCSI BUS reset */ ! 315: outb(0x20, LCL_DOORBELL_INTR(PORT_ADDRESS)); ! 316: /* Wait for completion... */ ! 317: do ! 318: in_byte = inb(LCL_DOORBELL_INTR(PORT_ADDRESS)); ! 319: while (in_byte & 0x20); ! 320: ! 321: aborted = DID_RESET; ! 322: ! 323: #ifdef DEBUG ! 324: printk("ultrastor_14f_reset: returning\n"); ! 325: #endif ! 326: return 0; ! 327: } ! 328: ! 329: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.