|
|
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.