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