|
|
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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.