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