adding GNU dc ("desk calculator")
[unix-history] / sys / i386 / stand / as.c
CommitLineData
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
30int as_port = 0x330;
31
32struct mailbox_entry mailbox[2];
33
34int
35asopen(io)
36struct 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{
110extern 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 */
126int
127asstrategy(io, func)
128struct 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
175int
176ascmd (target, readflag, cdb, cdblen, data, datalen, printerr)
177int target;
178int readflag;
179char *cdb;
180int cdblen;
181char *data;
182int datalen;
183int 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
267int
268as_put_byte (val)
269int val;
270{
271 while (inb (as_port + AS_STATUS) & AS_STATUS_CDF)
272 ;
273 outb (as_port + AS_DATA_OUT, val);
274}
275