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