Commit | Line | Data |
---|---|---|
15637ed4 RG |
1 | /* |
2 | * sys/i386/stand/as.c | |
3 | * | |
4 | * Standalone driver for Adaptech 1542 SCSI | |
5 | * | |
6 | * Pace Willisson pace@blitz.com April 8, 1992 | |
7 | * | |
8 | * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE | |
9 | * -------------------- ----- ---------------------- | |
10 | * CURRENT PATCH LEVEL: 1 00088 | |
11 | * -------------------- ----- ---------------------- | |
12 | * | |
13 | * 23 Oct 92 Joerg Lohse changed ccb opcode for compatibility | |
14 | * with Adaptec AHA-1542A | |
15 | */ | |
16 | ||
17 | #include "param.h" | |
18 | #include "disklabel.h" | |
19 | #include "i386/isa/asreg.h" | |
20 | #include "saio.h" | |
21 | ||
22 | #ifdef ASDEBUG | |
23 | #define ASPRINT(x) { printf x; DELAY (10000); } | |
24 | #else | |
25 | #define ASPRINT(x) | |
26 | #endif | |
27 | ||
28 | #define NRETRIES 3 | |
29 | ||
30 | int as_port = 0x330; | |
31 | ||
32 | struct mailbox_entry mailbox[2]; | |
33 | ||
34 | int | |
35 | asopen(io) | |
36 | struct iob *io; | |
37 | { | |
38 | struct disklabel *dd; | |
39 | char cdb[6]; | |
40 | char data[12]; | |
41 | int val; | |
42 | int oval; | |
43 | int i; | |
44 | struct iob aio; | |
45 | ||
46 | if (io->i_unit < 0 || io->i_unit > 8 | |
47 | || io->i_part < 0 || io->i_part > 8 | |
48 | || io->i_ctlr < 0 || io->i_ctlr > 0) | |
49 | return (-1); | |
50 | ||
51 | /* dma setup: see page 5-31 in the Adaptech manual */ | |
52 | outb (0xd6, 0xc1); | |
53 | outb (0xd4, 0x01); | |
54 | ||
55 | ASPRINT (("resetting adaptech card... ")); | |
56 | ||
57 | outb (as_port + AS_CONTROL, AS_CONTROL_SRST); | |
58 | ||
59 | /* delay a little */ | |
60 | for (i = 0; i < 100; i++) | |
61 | inb (0x84); | |
62 | ||
63 | while (inb (as_port + AS_STATUS) != (AS_STATUS_INIT | AS_STATUS_IDLE)) | |
64 | ; | |
65 | ||
66 | ASPRINT (("reset ok ")); | |
67 | ||
68 | as_put_byte (AS_CMD_MAILBOX_INIT); | |
69 | as_put_byte (1); /* one mailbox out, one in */ | |
70 | as_put_byte ((int)mailbox >> 16); | |
71 | as_put_byte ((int)mailbox >> 8); | |
72 | as_put_byte ((int)mailbox); | |
73 | ||
74 | while (inb (as_port + AS_STATUS) & AS_STATUS_INIT) | |
75 | ; | |
76 | ||
77 | ASPRINT (("mailbox init ok ")); | |
78 | ||
79 | /* do mode select to set the logical block size */ | |
80 | bzero (cdb, 6); | |
81 | cdb[0] = 0x15; /* MODE SELECT */ | |
82 | cdb[4] = 12; /* parameter list length */ | |
83 | ||
84 | bzero (data, 12); | |
85 | data[3] = 8; /* block descriptor length */ | |
86 | data[9] = DEV_BSIZE >> 16; | |
87 | data[10] = DEV_BSIZE >> 8; | |
88 | data[11] = DEV_BSIZE; | |
89 | ||
90 | if (ascmd (io->i_unit, 0, cdb, 6, data, 12, 1) < 0) { | |
91 | printf ("as%d: error setting logical block size\n", | |
92 | io->i_unit); | |
93 | return (-1); | |
94 | } | |
95 | ||
96 | aio = *io; | |
97 | aio.i_bn = LABELSECTOR; | |
98 | aio.i_cc = DEV_BSIZE; | |
99 | /*io->i_ma = buf;*/ | |
100 | aio.i_boff = 0; | |
101 | ||
102 | #ifdef was | |
103 | if (asstrategy (&aio, F_READ) == DEV_BSIZE) { | |
104 | dd = (struct disklabel *)aio.i_ma; | |
105 | io->i_boff = dd->d_partitions[io->i_part].p_offset; | |
106 | ASPRINT (("partition offset %d ", io->i_boff)); | |
107 | } | |
108 | #else | |
109 | { | |
110 | extern struct disklabel disklabel; | |
111 | io->i_boff = disklabel.d_partitions[io->i_part].p_offset; | |
112 | ASPRINT (("partition offset %d ", io->i_boff)); | |
113 | } | |
114 | #endif | |
115 | ||
116 | ASPRINT (("asopen ok ")); | |
117 | return(0); | |
118 | } | |
119 | ||
120 | /* func is F_WRITE or F_READ | |
121 | * io->i_unit, io->i_part, io->i_bn is starting block | |
122 | * io->i_cc is byte count | |
123 | * io->i_ma is memory address | |
124 | * io->i_boff is block offset for this partition (set up in asopen) | |
125 | */ | |
126 | int | |
127 | asstrategy(io, func) | |
128 | struct iob *io; | |
129 | { | |
130 | char cdb[6]; | |
131 | int blkno; | |
132 | int retry; | |
133 | ||
134 | ASPRINT (("asstrategy(target=%d, block=%d+%d, count=%d) ", | |
135 | io->i_unit, io->i_bn, io->i_boff, io->i_cc)); | |
136 | ||
137 | if (func == F_WRITE) { | |
138 | printf ("as%d: write not supported\n", io->i_unit); | |
139 | return (0); | |
140 | } | |
141 | ||
142 | if (io->i_cc == 0) | |
143 | return (0); | |
144 | ||
145 | if (io->i_cc % DEV_BSIZE != 0) { | |
146 | printf ("as%d: transfer size not multiple of %d\n", | |
147 | io->i_unit, DEV_BSIZE); | |
148 | return (0); | |
149 | } | |
150 | ||
151 | /* retry in case we get a unit-attention error, which just | |
152 | * means the drive has been reset since the last command | |
153 | */ | |
154 | for (retry = 0; retry < NRETRIES; retry++) { | |
155 | blkno = io->i_bn + io->i_boff; | |
156 | ||
157 | cdb[0] = 8; /* scsi read opcode */ | |
158 | cdb[1] = (blkno >> 16) & 0x1f; | |
159 | cdb[2] = blkno >> 8; | |
160 | cdb[3] = blkno; | |
161 | cdb[4] = io->i_cc / DEV_BSIZE; | |
162 | cdb[5] = 0; /* control byte (used in linking) */ | |
163 | ||
164 | if (ascmd (io->i_unit, 1, cdb, 6, io->i_ma, io->i_cc, | |
165 | retry == NRETRIES - 1) >= 0) { | |
166 | ASPRINT (("asstrategy ok ")); | |
167 | return (io->i_cc); | |
168 | } | |
169 | } | |
170 | ||
171 | ASPRINT (("asstrategy failed ")); | |
172 | return (0); | |
173 | } | |
174 | ||
175 | int | |
176 | ascmd (target, readflag, cdb, cdblen, data, datalen, printerr) | |
177 | int target; | |
178 | int readflag; | |
179 | char *cdb; | |
180 | int cdblen; | |
181 | char *data; | |
182 | int datalen; | |
183 | int printerr; | |
184 | { | |
185 | struct ccb ccb; | |
186 | int physaddr; | |
187 | unsigned char *sp; | |
188 | int i; | |
189 | ||
190 | if (mailbox[0].cmd != 0) | |
191 | /* this can't happen, unless the card flakes */ | |
192 | _stop ("asstart: mailbox not available\n"); | |
193 | ||
194 | bzero (&ccb, sizeof ccb); | |
195 | ||
196 | ccb.ccb_opcode = 0; | |
197 | ccb.ccb_addr_and_control = target << 5; | |
198 | if (datalen != 0) | |
199 | ccb.ccb_addr_and_control |= readflag ? 8 : 0x10; | |
200 | else | |
201 | ccb.ccb_addr_and_control |= 0x18; | |
202 | ||
203 | ccb.ccb_data_len_msb = datalen >> 16; | |
204 | ccb.ccb_data_len_mid = datalen >> 8; | |
205 | ccb.ccb_data_len_lsb = datalen; | |
206 | ||
207 | ccb.ccb_requst_sense_allocation_len = MAXSENSE; | |
208 | ||
209 | physaddr = (int)data; | |
210 | ccb.ccb_data_ptr_msb = physaddr >> 16; | |
211 | ccb.ccb_data_ptr_mid = physaddr >> 8; | |
212 | ccb.ccb_data_ptr_lsb = physaddr; | |
213 | ||
214 | ccb.ccb_scsi_command_len = cdblen; | |
215 | bcopy (cdb, ccb.ccb_cdb, cdblen); | |
216 | ||
217 | #ifdef ASDEBUG | |
218 | printf ("ccb: "); | |
219 | for (i = 0; i < 48; i++) | |
220 | printf ("%x ", ((unsigned char *)&ccb)[i]); | |
221 | printf ("\n"); | |
222 | /*getchar ();*/ | |
223 | #endif | |
224 | ||
225 | physaddr = (int)&ccb; | |
226 | mailbox[0].msb = physaddr >> 16; | |
227 | mailbox[0].mid = physaddr >> 8; | |
228 | mailbox[0].lsb = physaddr; | |
229 | mailbox[0].cmd = 1; | |
230 | ||
231 | /* tell controller to look in its mailbox */ | |
232 | outb (as_port + AS_CONTROL, AS_CONTROL_IRST); | |
233 | as_put_byte (AS_CMD_START_SCSI_COMMAND); | |
234 | ||
235 | /* wait for status */ | |
236 | ASPRINT (("waiting for status...")); | |
237 | while (mailbox[1].cmd == 0) | |
238 | ; | |
239 | mailbox[1].cmd = 0; | |
240 | ||
241 | ||
242 | if (ccb.ccb_host_status != 0 || ccb.ccb_target_status != 0) { | |
243 | #ifdef ASDEBUG | |
244 | printerr = 1; | |
245 | #endif | |
246 | if (printerr) { | |
247 | printf ("as%d error: hst=%x tst=%x sense=", | |
248 | target, | |
249 | ccb.ccb_host_status, | |
250 | ccb.ccb_target_status); | |
251 | sp = ccb_sense (&ccb); | |
252 | for (i = 0; i < 8; i++) | |
253 | printf ("%x ", sp[i]); | |
254 | printf ("\n"); | |
255 | #ifdef ASDEBUG | |
256 | /*getchar ();*/ | |
257 | #endif | |
258 | } | |
259 | return (-1); | |
260 | } | |
261 | ||
262 | ASPRINT (("ascmd ok ")); | |
263 | ||
264 | return (0); | |
265 | } | |
266 | ||
267 | int | |
268 | as_put_byte (val) | |
269 | int val; | |
270 | { | |
271 | while (inb (as_port + AS_STATUS) & AS_STATUS_CDF) | |
272 | ; | |
273 | outb (as_port + AS_DATA_OUT, val); | |
274 | } | |
275 |