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