xref: /386bsd/usr/src/kernel/as/asboot.c (revision a2142627)
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