Commit | Line | Data |
---|---|---|
15637ed4 RG |
1 | /* |
2 | * Ported for use with the UltraStor 14f by Gary Close (gclose@wvnvms.wvnet.edu) | |
519fb2b7 | 3 | * Slight fixes to timeouts to run with the 34F |
15637ed4 RG |
4 | * Thanks to Julian Elischer for advice and help with this port. |
5 | * | |
6 | * Written by Julian Elischer (julian@tfs.com) | |
7 | * for TRW Financial Systems for use under the MACH(2.5) operating system. | |
8 | * | |
9 | * TRW Financial Systems, in accordance with their agreement with Carnegie | |
10 | * Mellon University, makes this software available to CMU to distribute | |
11 | * or use in any manner that they see fit as long as this message is kept with | |
12 | * the software. For this reason TFS also grants any other persons or | |
13 | * organisations permission to use or modify this software. | |
14 | * | |
15 | * TFS supplies this software to be publicly redistributed | |
16 | * on the understanding that TFS is not responsible for the correct | |
17 | * functioning of this software in any circumstances. | |
18 | * | |
b33502d5 | 19 | * commenced: Sun Sep 27 18:14:01 PDT 1992 |
b1ec887f | 20 | * slight mod to make work with 34F as well: Wed Jun 2 18:05:48 WST 1993 |
98639498 | 21 | * |
d1c49517 | 22 | * $Id: ultra14f.c,v 1.16 1994/03/20 00:30:04 wollman Exp $ |
15637ed4 | 23 | */ |
519fb2b7 | 24 | |
15637ed4 | 25 | #include <sys/types.h> |
519fb2b7 RG |
26 | |
27 | #ifdef KERNEL /* don't laugh.. this compiles to a program too.. look */ | |
15637ed4 RG |
28 | #include <uha.h> |
29 | ||
30 | #include <sys/param.h> | |
31 | #include <sys/systm.h> | |
32 | #include <sys/errno.h> | |
33 | #include <sys/ioctl.h> | |
519fb2b7 | 34 | #include <sys/malloc.h> |
15637ed4 RG |
35 | #include <sys/buf.h> |
36 | #include <sys/proc.h> | |
37 | #include <sys/user.h> | |
38 | ||
15637ed4 RG |
39 | #include <i386/include/pio.h> |
40 | #include <i386/isa/isa_device.h> | |
519fb2b7 | 41 | #endif /*KERNEL */ |
15637ed4 RG |
42 | #include <scsi/scsi_all.h> |
43 | #include <scsi/scsiconf.h> | |
15637ed4 | 44 | |
519fb2b7 | 45 | /*\f */ |
15637ed4 | 46 | |
519fb2b7 | 47 | #ifdef KERNEL |
15637ed4 | 48 | #include "ddb.h" |
519fb2b7 RG |
49 | #else /*KERNEL */ |
50 | #define NUHA 1 | |
51 | #endif /*KERNEL */ | |
52 | ||
53 | typedef struct { | |
54 | unsigned char addr[4]; | |
55 | } physaddr; | |
56 | typedef struct { | |
57 | unsigned char len[4]; | |
58 | } physlen; | |
15637ed4 | 59 | |
519fb2b7 | 60 | #define KVTOPHYS(x) vtophys(x) |
15637ed4 | 61 | |
519fb2b7 RG |
62 | #define UHA_MSCP_MAX 32 /* store up to 32MSCPs at any one time |
63 | * MAX = ? | |
64 | */ | |
65 | #define MSCP_HASH_SIZE 32 /* when we have a physical addr. for | |
66 | * a mscp and need to find the mscp in | |
67 | * space, look it up in the hash table | |
68 | */ | |
69 | #define MSCP_HASH_SHIFT 9 /* only hash on multiples of 512 */ | |
70 | #define MSCP_HASH(x) ((((long int)(x))>>MSCP_HASH_SHIFT) % MSCP_HASH_SIZE) | |
15637ed4 | 71 | |
519fb2b7 RG |
72 | extern int hz; |
73 | #define UHA_NSEG 33 /* number of dma segments supported */ | |
15637ed4 | 74 | |
15637ed4 RG |
75 | /************************** board definitions *******************************/ |
76 | /* | |
77 | * I/O Port Interface | |
519fb2b7 RG |
78 | */ |
79 | #define UHA_LMASK (0x000) /* local doorbell mask reg */ | |
80 | #define UHA_LINT (0x001) /* local doorbell int/stat reg */ | |
81 | #define UHA_SMASK (0x002) /* system doorbell mask reg */ | |
82 | #define UHA_SINT (0x003) /* system doorbell int/stat reg */ | |
83 | #define UHA_ID0 (0x004) /* product id reg 0 */ | |
84 | #define UHA_ID1 (0x005) /* product id reg 1 */ | |
85 | #define UHA_CONF1 (0x006) /* config reg 1 */ | |
86 | #define UHA_CONF2 (0x007) /* config reg 2 */ | |
87 | #define UHA_OGM0 (0x008) /* outgoing mail ptr 0 least sig */ | |
88 | #define UHA_OGM1 (0x009) /* outgoing mail ptr 1 least mid */ | |
89 | #define UHA_OGM2 (0x00a) /* outgoing mail ptr 2 most mid */ | |
90 | #define UHA_OGM3 (0x00b) /* outgoing mail ptr 3 most sig */ | |
91 | #define UHA_ICM0 (0x00c) /* incoming mail ptr 0 */ | |
92 | #define UHA_ICM1 (0x00d) /* incoming mail ptr 1 */ | |
93 | #define UHA_ICM2 (0x00e) /* incoming mail ptr 2 */ | |
94 | #define UHA_ICM3 (0x00f) /* incoming mail ptr 3 */ | |
15637ed4 RG |
95 | |
96 | /* | |
519fb2b7 RG |
97 | * UHA_LMASK bits (read only) |
98 | */ | |
15637ed4 | 99 | |
519fb2b7 RG |
100 | #define UHA_LDIE 0x80 /* local doorbell int enabled */ |
101 | #define UHA_SRSTE 0x40 /* soft reset enabled */ | |
102 | #define UHA_ABORTEN 0x10 /* abort MSCP enabled */ | |
103 | #define UHA_OGMINTEN 0x01 /* outgoing mail interrupt enabled */ | |
15637ed4 RG |
104 | |
105 | /* | |
519fb2b7 RG |
106 | * UHA_LINT bits (read) |
107 | */ | |
15637ed4 | 108 | |
519fb2b7 | 109 | #define UHA_LDIP 0x80 /* local doorbell int pending */ |
15637ed4 RG |
110 | |
111 | /* | |
519fb2b7 RG |
112 | * UHA_LINT bits (write) |
113 | */ | |
15637ed4 | 114 | |
519fb2b7 RG |
115 | #define UHA_ADRST 0x40 /* adapter soft reset */ |
116 | #define UHA_SBRST 0x20 /* scsi bus reset */ | |
117 | #define UHA_ASRST 0x60 /* adapter and scsi reset */ | |
118 | #define UHA_ABORT 0x10 /* abort MSCP */ | |
119 | #define UHA_OGMINT 0x01 /* tell adapter to get mail */ | |
15637ed4 RG |
120 | |
121 | /* | |
519fb2b7 RG |
122 | * UHA_SMASK bits (read) |
123 | */ | |
15637ed4 | 124 | |
519fb2b7 RG |
125 | #define UHA_SINTEN 0x80 /* system doorbell interupt Enabled */ |
126 | #define UHA_ABORT_COMPLETE_EN 0x10 /* abort MSCP command complete int Enabled */ | |
127 | #define UHA_ICM_ENABLED 0x01 /* ICM interrupt enabled */ | |
15637ed4 RG |
128 | |
129 | /* | |
519fb2b7 RG |
130 | * UHA_SMASK bits (write) |
131 | */ | |
15637ed4 | 132 | |
519fb2b7 RG |
133 | #define UHA_ENSINT 0x80 /* enable system doorbell interrupt */ |
134 | #define UHA_EN_ABORT_COMPLETE 0x10 /* enable abort MSCP complete int */ | |
135 | #define UHA_ENICM 0x01 /* enable ICM interrupt */ | |
15637ed4 RG |
136 | |
137 | /* | |
519fb2b7 RG |
138 | * UHA_SINT bits (read) |
139 | */ | |
140 | ||
141 | #define UHA_SINTP 0x80 /* system doorbell int pending */ | |
142 | #define UHA_ABORT_SUCC 0x10 /* abort MSCP successful */ | |
143 | #define UHA_ABORT_FAIL 0x18 /* abort MSCP failed */ | |
144 | ||
145 | /* | |
146 | * UHA_SINT bits (write) | |
147 | */ | |
15637ed4 | 148 | |
519fb2b7 RG |
149 | #define UHA_ABORT_ACK 0x18 /* acknowledge status and clear */ |
150 | #define UHA_ICM_ACK 0x01 /* acknowledge ICM and clear */ | |
15637ed4 RG |
151 | |
152 | /* | |
519fb2b7 RG |
153 | * UHA_CONF1 bits (read only) |
154 | */ | |
155 | ||
156 | #define UHA_DMA_CH5 0x00 /* DMA channel 5 */ | |
157 | #define UHA_DMA_CH6 0x40 /* 6 */ | |
158 | #define UHA_DMA_CH7 0x80 /* 7 */ | |
159 | #define UHA_IRQ15 0x00 /* IRQ 15 */ | |
160 | #define UHA_IRQ14 0x10 /* 14 */ | |
161 | #define UHA_IRQ11 0x20 /* 11 */ | |
162 | #define UHA_IRQ10 0x30 /* 10 */ | |
163 | ||
164 | /* | |
165 | * ha_status error codes | |
166 | */ | |
167 | ||
168 | #define UHA_NO_ERR 0x00 /* No error supposedly */ | |
169 | #define UHA_SBUS_ABORT_ERR 0x84 /* scsi bus abort error */ | |
170 | #define UHA_SBUS_TIMEOUT 0x91 /* scsi bus selection timeout */ | |
171 | #define UHA_SBUS_OVER_UNDER 0x92 /* scsi bus over/underrun */ | |
172 | #define UHA_BAD_SCSI_CMD 0x96 /* illegal scsi command */ | |
173 | #define UHA_AUTO_SENSE_ERR 0x9b /* auto request sense err */ | |
174 | #define UHA_SBUS_RES_ERR 0xa3 /* scsi bus reset error */ | |
175 | #define UHA_BAD_SG_LIST 0xff /* invalid scatter gath list */ | |
176 | ||
177 | struct uha_dma_seg { | |
178 | physaddr addr; | |
179 | physlen len; | |
15637ed4 | 180 | }; |
15637ed4 | 181 | |
519fb2b7 RG |
182 | struct mscp { |
183 | unsigned char opcode:3; | |
184 | #define U14_HAC 0x01 /* host adapter command */ | |
185 | #define U14_TSP 0x02 /* target scsi pass through command */ | |
186 | #define U14_SDR 0x04 /* scsi device reset */ | |
187 | unsigned char xdir:2; /* xfer direction */ | |
188 | #define U14_SDET 0x00 /* determined by scsi command */ | |
189 | #define U14_SDIN 0x01 /* scsi data in */ | |
190 | #define U14_SDOUT 0x02 /* scsi data out */ | |
191 | #define U14_NODATA 0x03 /* no data xfer */ | |
192 | unsigned char dcn:1; /* disable disconnect for this command */ | |
193 | unsigned char ca:1; /* cache control */ | |
194 | unsigned char sgth:1; /* scatter gather flag */ | |
195 | unsigned char target:3; | |
196 | unsigned char chan:2; /* scsi channel (always 0 for 14f) */ | |
197 | unsigned char lun:3; | |
198 | physaddr data; | |
199 | physlen datalen; | |
200 | physaddr link; | |
201 | unsigned char link_id; | |
202 | unsigned char sg_num; /*number of scat gath segs */ | |
203 | /*in s-g list if sg flag is */ | |
204 | /*set. starts at 1, 8bytes per */ | |
205 | unsigned char senselen; | |
206 | unsigned char cdblen; | |
207 | unsigned char cdb[12]; | |
208 | unsigned char ha_status; | |
209 | unsigned char targ_status; | |
210 | physaddr sense; /* if 0 no auto sense */ | |
15637ed4 | 211 | /*-----------------end of hardware supported fields----------------*/ |
519fb2b7 RG |
212 | struct mscp *next; /* in free list */ |
213 | struct scsi_xfer *xs; /* the scsi_xfer for this cmd */ | |
214 | int flags; | |
15637ed4 RG |
215 | #define MSCP_FREE 0 |
216 | #define MSCP_ACTIVE 1 | |
217 | #define MSCP_ABORTED 2 | |
519fb2b7 RG |
218 | struct uha_dma_seg uha_dma[UHA_NSEG]; |
219 | struct scsi_sense_data mscp_sense; | |
220 | struct mscp *nexthash; | |
221 | long int hashkey; | |
15637ed4 RG |
222 | }; |
223 | ||
519fb2b7 | 224 | struct uha_data { |
15637ed4 RG |
225 | int flags; |
226 | #define UHA_INIT 0x01; | |
227 | int baseport; | |
519fb2b7 RG |
228 | struct mscp *mscphash[MSCP_HASH_SIZE]; |
229 | struct mscp *free_mscp; | |
230 | int our_id; /* our scsi id */ | |
15637ed4 | 231 | int vect; |
519fb2b7 RG |
232 | int dma; |
233 | int nummscps; | |
234 | struct scsi_link sc_link; | |
235 | } *uhadata[NUHA]; | |
15637ed4 RG |
236 | |
237 | int uhaprobe(); | |
238 | int uha_attach(); | |
239 | int uhaintr(); | |
519fb2b7 | 240 | int32 uha_scsi_cmd(); |
4c45483e | 241 | void uha_timeout(caddr_t, int); |
519fb2b7 RG |
242 | void uha_free_mscp(); |
243 | int uha_abort(); | |
15637ed4 | 244 | void uhaminphys(); |
519fb2b7 RG |
245 | void uha_done(); |
246 | u_int32 uha_adapter_info(); | |
247 | struct mscp *uha_mscp_phys_kv(); | |
15637ed4 | 248 | |
519fb2b7 | 249 | struct mscp *cheat; |
15637ed4 | 250 | unsigned long int scratch; |
519fb2b7 | 251 | static uha_unit = 0; |
15637ed4 RG |
252 | #define UHA_SHOWMSCPS 0x01 |
253 | #define UHA_SHOWINTS 0x02 | |
254 | #define UHA_SHOWCMDS 0x04 | |
255 | #define UHA_SHOWMISC 0x08 | |
256 | #define FAIL 1 | |
257 | #define SUCCESS 0 | |
258 | #define PAGESIZ 4096 | |
259 | ||
519fb2b7 RG |
260 | #ifdef KERNEL |
261 | struct isa_driver uhadriver = | |
262 | { | |
263 | uhaprobe, | |
264 | uha_attach, | |
265 | "uha" | |
266 | }; | |
267 | ||
268 | struct scsi_adapter uha_switch = | |
15637ed4 RG |
269 | { |
270 | uha_scsi_cmd, | |
271 | uhaminphys, | |
272 | 0, | |
273 | 0, | |
274 | uha_adapter_info, | |
3e9a2bcb | 275 | "uha", |
519fb2b7 | 276 | 0, 0 |
15637ed4 RG |
277 | }; |
278 | ||
519fb2b7 RG |
279 | /* the below structure is so we have a default dev struct for out link struct */ |
280 | struct scsi_device uha_dev = | |
15637ed4 | 281 | { |
519fb2b7 RG |
282 | NULL, /* Use default error handler */ |
283 | NULL, /* have a queue, served by this */ | |
284 | NULL, /* have no async handler */ | |
285 | NULL, /* Use default 'done' routine */ | |
286 | "uha", | |
287 | 0, | |
288 | 0, 0 | |
289 | }; | |
290 | ||
291 | #endif /*KERNEL */ | |
292 | ||
293 | #ifndef KERNEL | |
294 | main() | |
295 | { | |
296 | printf("uha_data is %d bytes\n", sizeof(struct uha_data)); | |
297 | printf("mscp is %d bytes\n", sizeof(struct mscp)); | |
298 | } | |
299 | ||
300 | #else /*KERNEL*/ | |
301 | /* | |
302 | * Function to send a command out through a mailbox | |
303 | */ | |
304 | void | |
305 | uha_send_mbox(int unit, struct mscp *mscp) | |
306 | { | |
307 | struct uha_data *uha = uhadata[unit]; | |
308 | int port = uha->baseport; | |
309 | int spincount = 100000; /* 1s should be enough */ | |
15637ed4 | 310 | int s = splbio(); |
519fb2b7 RG |
311 | |
312 | while (--spincount) { | |
313 | if ((inb(port + UHA_LINT) & UHA_LDIP) == 0) | |
314 | break; | |
315 | DELAY(100); | |
316 | } | |
317 | if (spincount == 0) { | |
318 | printf("uha%d: uha_send_mbox, board not responding\n", unit); | |
fde1aeb2 | 319 | Debugger("ultra14f"); |
15637ed4 | 320 | } |
519fb2b7 | 321 | outl(port + UHA_OGM0, KVTOPHYS(mscp)); |
15637ed4 RG |
322 | outb(port + UHA_LINT, (UHA_OGMINT)); |
323 | splx(s); | |
324 | } | |
325 | ||
519fb2b7 RG |
326 | /* |
327 | * Function to send abort to 14f | |
328 | */ | |
329 | int | |
330 | uha_abort(int unit, struct mscp *mscp) | |
15637ed4 | 331 | { |
519fb2b7 RG |
332 | struct uha_data *uha = uhadata[unit]; |
333 | int port = uha->baseport; | |
334 | int spincount = 100; /* 1 mSec */ | |
335 | int abortcount = 200000; /*2 secs */ | |
336 | int s = splbio(); | |
337 | ||
338 | while (--spincount) { | |
339 | if ((inb(port + UHA_LINT) & UHA_LDIP) == 0) | |
340 | break; | |
341 | DELAY(10); | |
342 | } | |
150c775c | 343 | if (spincount == 0) { |
519fb2b7 | 344 | printf("uha%d: uha_abort, board not responding\n", unit); |
fde1aeb2 | 345 | Debugger("ultra14f"); |
15637ed4 | 346 | } |
519fb2b7 RG |
347 | outl(port + UHA_OGM0, KVTOPHYS(mscp)); |
348 | outb(port + UHA_LINT, UHA_ABORT); | |
15637ed4 | 349 | |
519fb2b7 RG |
350 | while (--abortcount) { |
351 | if (inb(port + UHA_SINT) & UHA_ABORT_FAIL) | |
352 | break; | |
353 | DELAY(10); | |
15637ed4 | 354 | } |
519fb2b7 RG |
355 | if (abortcount == 0) { |
356 | printf("uha%d: uha_abort, board not responding\n", unit); | |
fde1aeb2 | 357 | Debugger("ultra14f"); |
15637ed4 | 358 | } |
519fb2b7 RG |
359 | if ((inb(port + UHA_SINT) & 0x10) != 0) { |
360 | outb(port + UHA_SINT, UHA_ABORT_ACK); | |
150c775c | 361 | splx(s); |
519fb2b7 RG |
362 | return (1); |
363 | } else { | |
364 | outb(port + UHA_SINT, UHA_ABORT_ACK); | |
150c775c | 365 | splx(s); |
519fb2b7 | 366 | return (0); |
15637ed4 RG |
367 | } |
368 | } | |
369 | ||
519fb2b7 RG |
370 | /* |
371 | * Function to poll for command completion when in poll mode. | |
372 | * | |
373 | * wait = timeout in msec | |
374 | */ | |
375 | int | |
376 | uha_poll(int unit, int wait) | |
15637ed4 | 377 | { |
519fb2b7 RG |
378 | struct uha_data *uha = uhadata[unit]; |
379 | int port = uha->baseport; | |
380 | int stport = port + UHA_SINT; | |
381 | ||
382 | retry: | |
383 | while (--wait) { | |
384 | if (inb(stport) & UHA_SINTP) | |
385 | break; | |
386 | DELAY(1000); /* 1 mSec per loop */ | |
387 | } | |
388 | if (wait == 0) { | |
389 | printf("uha%d: uha_poll, board not responding\n", unit); | |
390 | return (EIO); | |
15637ed4 | 391 | } |
15637ed4 | 392 | uhaintr(unit); |
519fb2b7 | 393 | return (0); |
15637ed4 RG |
394 | } |
395 | ||
519fb2b7 RG |
396 | /* |
397 | * Check if the device can be found at the port given and if so, set it up | |
398 | * ready for further work as an argument, takes the isa_device structure | |
399 | * from autoconf.c | |
400 | */ | |
401 | int | |
15637ed4 | 402 | uhaprobe(dev) |
519fb2b7 | 403 | struct isa_device *dev; |
15637ed4 | 404 | { |
519fb2b7 RG |
405 | int unit = uha_unit; |
406 | struct uha_data *uha; | |
15637ed4 | 407 | |
519fb2b7 | 408 | dev->id_unit = unit; |
15637ed4 | 409 | |
519fb2b7 RG |
410 | /* |
411 | * find unit and check we have that many defined | |
412 | */ | |
413 | if (unit >= NUHA) { | |
414 | printf("uha: unit number (%d) too high\n", unit); | |
415 | return (0); | |
416 | } | |
417 | dev->id_unit = unit; | |
418 | ||
419 | /* | |
420 | * Allocate a storage area for us | |
421 | */ | |
422 | if (uhadata[unit]) { | |
423 | printf("uha%d: memory already allocated\n", unit); | |
424 | return 0; | |
425 | } | |
426 | uha = malloc(sizeof(struct uha_data), M_TEMP, M_NOWAIT); | |
427 | if (!uha) { | |
428 | printf("uha%d: cannot malloc!\n", unit); | |
429 | return 0; | |
430 | } | |
431 | bzero(uha, sizeof(struct uha_data)); | |
432 | uhadata[unit] = uha; | |
433 | uha->baseport = dev->id_iobase; | |
434 | /* | |
435 | * Try initialise a unit at this location | |
436 | * sets up dma and bus speed, loads uha->vect | |
437 | */ | |
438 | if (uha_init(unit) != 0) { | |
439 | uhadata[unit] = NULL; | |
440 | free(uha, M_TEMP); | |
441 | return (0); | |
442 | } | |
443 | /* if it's there put in its interrupt and DRQ vectors */ | |
444 | dev->id_irq = (1 << uha->vect); | |
445 | dev->id_drq = uha->dma; | |
15637ed4 | 446 | |
519fb2b7 RG |
447 | uha_unit++; |
448 | return (16); | |
15637ed4 RG |
449 | } |
450 | ||
519fb2b7 RG |
451 | /* |
452 | * Attach all the sub-devices we can find | |
453 | */ | |
454 | int | |
15637ed4 | 455 | uha_attach(dev) |
519fb2b7 | 456 | struct isa_device *dev; |
15637ed4 | 457 | { |
519fb2b7 RG |
458 | int unit = dev->id_unit; |
459 | struct uha_data *uha = uhadata[unit]; | |
460 | ||
461 | /* | |
462 | * fill in the prototype scsi_link. | |
463 | */ | |
464 | uha->sc_link.adapter_unit = unit; | |
465 | uha->sc_link.adapter_targ = uha->our_id; | |
466 | uha->sc_link.adapter = &uha_switch; | |
467 | uha->sc_link.device = &uha_dev; | |
d1c49517 | 468 | uha->sc_link.flags = SDEV_BOUNCE; |
519fb2b7 RG |
469 | |
470 | /* | |
471 | * ask the adapter what subunits are present | |
472 | */ | |
473 | scsi_attachdevs(&(uha->sc_link)); | |
474 | ||
475 | return 1; | |
15637ed4 RG |
476 | } |
477 | ||
519fb2b7 RG |
478 | /* |
479 | * Return some information to the caller about | |
480 | * the adapter and it's capabilities | |
481 | */ | |
482 | u_int32 | |
483 | uha_adapter_info(unit) | |
484 | int unit; | |
15637ed4 | 485 | { |
519fb2b7 | 486 | return (2); /* 2 outstanding requests at a time per device */ |
15637ed4 RG |
487 | } |
488 | ||
519fb2b7 RG |
489 | /* |
490 | * Catch an interrupt from the adaptor | |
491 | */ | |
492 | int | |
15637ed4 | 493 | uhaintr(unit) |
4c45483e | 494 | int unit; |
15637ed4 | 495 | { |
519fb2b7 RG |
496 | struct uha_data *uha = uhadata[unit]; |
497 | struct mscp *mscp; | |
498 | u_char uhastat; | |
499 | unsigned long int mboxval; | |
15637ed4 | 500 | |
519fb2b7 | 501 | int port = uha->baseport; |
15637ed4 | 502 | |
b33502d5 | 503 | #ifdef UHADEBUG |
519fb2b7 RG |
504 | printf("uhaintr "); |
505 | #endif /*UHADEBUG */ | |
506 | ||
507 | while (inb(port + UHA_SINT) & UHA_SINTP) { | |
508 | /* | |
509 | * First get all the information and then | |
510 | * acknowledge the interrupt | |
511 | */ | |
15637ed4 RG |
512 | uhastat = inb(port + UHA_SINT); |
513 | mboxval = inl(port + UHA_ICM0); | |
519fb2b7 | 514 | outb(port + UHA_SINT, UHA_ICM_ACK); |
15637ed4 | 515 | |
b33502d5 | 516 | #ifdef UHADEBUG |
519fb2b7 RG |
517 | printf("status = 0x%x ", uhastat); |
518 | #endif /*UHADEBUG*/ | |
519 | /* | |
520 | * Process the completed operation | |
521 | */ | |
522 | ||
523 | mscp = uha_mscp_phys_kv(uha, mboxval); | |
524 | if (!mscp) { | |
525 | printf("uha: BAD MSCP RETURNED\n"); | |
526 | return (0); /* whatever it was, it'll timeout */ | |
527 | } | |
fde1aeb2 | 528 | untimeout(uha_timeout, (caddr_t)mscp); |
15637ed4 | 529 | |
519fb2b7 | 530 | uha_done(unit, mscp); |
15637ed4 | 531 | } |
519fb2b7 | 532 | return (1); |
15637ed4 RG |
533 | } |
534 | ||
519fb2b7 RG |
535 | /* |
536 | * We have a mscp which has been processed by the adaptor, now we look to see | |
537 | * how the operation went. | |
538 | */ | |
539 | void | |
540 | uha_done(unit, mscp) | |
541 | int unit; | |
542 | struct mscp *mscp; | |
15637ed4 | 543 | { |
519fb2b7 RG |
544 | struct uha_data *uha = uhadata[unit]; |
545 | struct scsi_sense_data *s1, *s2; | |
546 | struct scsi_xfer *xs = mscp->xs; | |
547 | ||
548 | SC_DEBUG(xs->sc_link, SDEV_DB2, ("uha_done\n")); | |
549 | /* | |
550 | * Otherwise, put the results of the operation | |
551 | * into the xfer and call whoever started it | |
552 | */ | |
553 | if ((mscp->ha_status == UHA_NO_ERR) || (xs->flags & SCSI_ERR_OK)) { /* All went correctly OR errors expected */ | |
15637ed4 RG |
554 | xs->resid = 0; |
555 | xs->error = 0; | |
519fb2b7 | 556 | } else { |
15637ed4 RG |
557 | |
558 | s1 = &(mscp->mscp_sense); | |
559 | s2 = &(xs->sense); | |
560 | ||
519fb2b7 RG |
561 | if (mscp->ha_status != UHA_NO_ERR) { |
562 | switch (mscp->ha_status) { | |
563 | case UHA_SBUS_TIMEOUT: /* No response */ | |
564 | SC_DEBUG(xs->sc_link, SDEV_DB3, | |
565 | ("timeout reported back\n")); | |
15637ed4 RG |
566 | xs->error = XS_TIMEOUT; |
567 | break; | |
519fb2b7 RG |
568 | case UHA_SBUS_OVER_UNDER: |
569 | SC_DEBUG(xs->sc_link, SDEV_DB3, | |
570 | ("scsi bus xfer over/underrun\n")); | |
15637ed4 RG |
571 | xs->error = XS_DRIVER_STUFFUP; |
572 | break; | |
519fb2b7 RG |
573 | case UHA_BAD_SG_LIST: |
574 | SC_DEBUG(xs->sc_link, SDEV_DB3, | |
575 | ("bad sg list reported back\n")); | |
15637ed4 RG |
576 | xs->error = XS_DRIVER_STUFFUP; |
577 | break; | |
519fb2b7 | 578 | default: /* Other scsi protocol messes */ |
15637ed4 | 579 | xs->error = XS_DRIVER_STUFFUP; |
519fb2b7 RG |
580 | SC_DEBUG(xs->sc_link, SDEV_DB3, |
581 | ("unexpected ha_status: %x\n", | |
582 | mscp->ha_status)); | |
15637ed4 | 583 | } |
519fb2b7 | 584 | } else { |
15637ed4 RG |
585 | |
586 | if (mscp->targ_status != 0) | |
519fb2b7 RG |
587 | /* |
588 | * I have no information for any possible value of target status field | |
589 | * other than 0 means no error!! So I guess any error is unexpected in that | |
590 | * event!! | |
591 | */ | |
15637ed4 | 592 | |
519fb2b7 RG |
593 | { |
594 | SC_DEBUG(xs->sc_link, SDEV_DB3, | |
595 | ("unexpected targ_status: %x\n", | |
596 | mscp->targ_status)); | |
15637ed4 RG |
597 | xs->error = XS_DRIVER_STUFFUP; |
598 | } | |
599 | } | |
519fb2b7 RG |
600 | } |
601 | done: | |
602 | xs->flags |= ITSDONE; | |
603 | uha_free_mscp(unit, mscp, xs->flags); | |
604 | scsi_done(xs); | |
15637ed4 RG |
605 | } |
606 | ||
519fb2b7 RG |
607 | /* |
608 | * A mscp (and hence a mbx-out) is put onto the free list. | |
609 | */ | |
610 | void | |
611 | uha_free_mscp(unit, mscp, flags) | |
4c45483e | 612 | int unit; |
519fb2b7 | 613 | struct mscp *mscp; |
4c45483e | 614 | int flags; |
15637ed4 | 615 | { |
519fb2b7 | 616 | struct uha_data *uha = uhadata[unit]; |
4c45483e | 617 | unsigned int opri = 0; |
519fb2b7 RG |
618 | |
619 | if (!(flags & SCSI_NOMASK)) | |
15637ed4 RG |
620 | opri = splbio(); |
621 | ||
519fb2b7 RG |
622 | mscp->next = uha->free_mscp; |
623 | uha->free_mscp = mscp; | |
15637ed4 | 624 | mscp->flags = MSCP_FREE; |
519fb2b7 RG |
625 | /* |
626 | * If there were none, wake abybody waiting for | |
627 | * one to come free, starting with queued entries | |
628 | */ | |
15637ed4 | 629 | if (!mscp->next) { |
4c45483e | 630 | wakeup((caddr_t)&uha->free_mscp); |
15637ed4 | 631 | } |
519fb2b7 | 632 | if (!(flags & SCSI_NOMASK)) |
15637ed4 RG |
633 | splx(opri); |
634 | } | |
635 | ||
519fb2b7 RG |
636 | /* |
637 | * Get a free mscp | |
638 | * | |
639 | * If there are none, see if we can allocate a new one. If so, put it in the | |
640 | * hash table too otherwise either return an error or sleep. | |
641 | */ | |
15637ed4 | 642 | struct mscp * |
519fb2b7 RG |
643 | uha_get_mscp(unit, flags) |
644 | int unit, flags; | |
15637ed4 | 645 | { |
519fb2b7 | 646 | struct uha_data *uha = uhadata[unit]; |
4c45483e | 647 | unsigned opri = 0; |
519fb2b7 RG |
648 | struct mscp *mscpp; |
649 | int hashnum; | |
15637ed4 | 650 | |
519fb2b7 | 651 | if (!(flags & SCSI_NOMASK)) |
15637ed4 | 652 | opri = splbio(); |
519fb2b7 RG |
653 | /* |
654 | * If we can and have to, sleep waiting for one to come free | |
655 | * but only if we can't allocate a new one | |
656 | */ | |
657 | while (!(mscpp = uha->free_mscp)) { | |
658 | if (uha->nummscps < UHA_MSCP_MAX) { | |
659 | if (mscpp = (struct mscp *)malloc(sizeof(struct mscp), | |
660 | M_TEMP, | |
661 | M_NOWAIT)) { | |
662 | bzero(mscpp, sizeof(struct mscp)); | |
663 | uha->nummscps++; | |
664 | mscpp->flags = MSCP_ACTIVE; | |
665 | /* | |
666 | * put in the phystokv hash table | |
667 | * Never gets taken out. | |
668 | */ | |
669 | mscpp->hashkey = KVTOPHYS(mscpp); | |
670 | hashnum = MSCP_HASH(mscpp->hashkey); | |
671 | mscpp->nexthash = uha->mscphash[hashnum]; | |
672 | uha->mscphash[hashnum] = mscpp; | |
673 | } else { | |
674 | printf("uha%d: Can't malloc MSCP\n", unit); | |
675 | } | |
676 | goto gottit; | |
677 | } else { | |
678 | if (!(flags & SCSI_NOSLEEP)) { | |
ee874879 GW |
679 | tsleep((caddr_t)&uha->free_mscp, PRIBIO, |
680 | "uhamscp", 0); | |
519fb2b7 RG |
681 | } |
682 | } | |
15637ed4 | 683 | } |
519fb2b7 RG |
684 | if (mscpp) { |
685 | /* Get MSCP from from free list */ | |
686 | uha->free_mscp = mscpp->next; | |
687 | mscpp->flags = MSCP_ACTIVE; | |
15637ed4 | 688 | } |
519fb2b7 RG |
689 | gottit: |
690 | if (!(flags & SCSI_NOMASK)) | |
15637ed4 | 691 | splx(opri); |
519fb2b7 RG |
692 | |
693 | return (mscpp); | |
15637ed4 | 694 | } |
15637ed4 | 695 | |
519fb2b7 RG |
696 | /* |
697 | * given a physical address, find the mscp that it corresponds to. | |
698 | */ | |
699 | struct mscp * | |
700 | uha_mscp_phys_kv(uha, mscp_phys) | |
701 | struct uha_data *uha; | |
702 | long int mscp_phys; | |
703 | { | |
704 | int hashnum = MSCP_HASH(mscp_phys); | |
705 | struct mscp *mscpp = uha->mscphash[hashnum]; | |
15637ed4 | 706 | |
519fb2b7 RG |
707 | while (mscpp) { |
708 | if (mscpp->hashkey == mscp_phys) | |
709 | break; | |
710 | mscpp = mscpp->nexthash; | |
711 | } | |
712 | return mscpp; | |
713 | } | |
15637ed4 | 714 | |
519fb2b7 RG |
715 | /* |
716 | * Start the board, ready for normal operation | |
717 | */ | |
718 | int | |
15637ed4 | 719 | uha_init(unit) |
519fb2b7 RG |
720 | int unit; |
721 | { | |
722 | struct uha_data *uha = uhadata[unit]; | |
15637ed4 RG |
723 | unsigned char ad[4]; |
724 | volatile unsigned char model; | |
725 | volatile unsigned char submodel; | |
726 | unsigned char config_reg1; | |
727 | unsigned char config_reg2; | |
728 | unsigned char dma_ch; | |
729 | unsigned char irq_ch; | |
730 | unsigned char uha_id; | |
519fb2b7 RG |
731 | int port = uha->baseport; |
732 | int i; | |
733 | int resetcount = 4000; /* 4 secs? */ | |
15637ed4 RG |
734 | |
735 | model = inb(port + UHA_ID0); | |
736 | submodel = inb(port + UHA_ID1); | |
519fb2b7 RG |
737 | if ((model != 0x56) & (submodel != 0x40)) { |
738 | printf("uha%d: uha_init, board not responding\n", unit); | |
739 | return (ENXIO); | |
740 | } | |
741 | printf("uha%d: reading board settings, ", unit); | |
15637ed4 RG |
742 | |
743 | config_reg1 = inb(port + UHA_CONF1); | |
744 | config_reg2 = inb(port + UHA_CONF2); | |
745 | dma_ch = (config_reg1 & 0xc0); | |
746 | irq_ch = (config_reg1 & 0x30); | |
747 | uha_id = (config_reg2 & 0x07); | |
748 | ||
519fb2b7 RG |
749 | switch (dma_ch) { |
750 | case UHA_DMA_CH5: | |
751 | uha->dma = 5; | |
15637ed4 RG |
752 | printf("dma=5 "); |
753 | break; | |
519fb2b7 RG |
754 | case UHA_DMA_CH6: |
755 | uha->dma = 6; | |
15637ed4 RG |
756 | printf("dma=6 "); |
757 | break; | |
519fb2b7 RG |
758 | case UHA_DMA_CH7: |
759 | uha->dma = 7; | |
15637ed4 RG |
760 | printf("dma=7 "); |
761 | break; | |
762 | default: | |
763 | printf("illegal dma jumper setting\n"); | |
519fb2b7 | 764 | return (EIO); |
15637ed4 | 765 | } |
519fb2b7 RG |
766 | switch (irq_ch) { |
767 | case UHA_IRQ10: | |
768 | uha->vect = 10; | |
15637ed4 RG |
769 | printf("int=10 "); |
770 | break; | |
519fb2b7 RG |
771 | case UHA_IRQ11: |
772 | uha->vect = 11; | |
15637ed4 RG |
773 | printf("int=11 "); |
774 | break; | |
519fb2b7 RG |
775 | case UHA_IRQ14: |
776 | uha->vect = 14; | |
15637ed4 RG |
777 | printf("int=14 "); |
778 | break; | |
519fb2b7 RG |
779 | case UHA_IRQ15: |
780 | uha->vect = 15; | |
15637ed4 RG |
781 | printf("int=15 "); |
782 | break; | |
783 | default: | |
784 | printf("illegal int jumper setting\n"); | |
519fb2b7 | 785 | return (EIO); |
15637ed4 | 786 | } |
519fb2b7 | 787 | |
15637ed4 | 788 | /* who are we on the scsi bus */ |
519fb2b7 RG |
789 | printf("id=%x\n", uha_id); |
790 | uha->our_id = uha_id; | |
791 | ||
792 | /* | |
793 | * Note that we are going and return (to probe) | |
794 | */ | |
795 | outb(port + UHA_LINT, UHA_ASRST); | |
796 | while (--resetcount) { | |
150c775c RG |
797 | if (inb(port + UHA_LINT)) |
798 | break; | |
519fb2b7 | 799 | DELAY(1000); /* 1 mSec per loop */ |
15637ed4 | 800 | } |
519fb2b7 RG |
801 | if (resetcount == 0) { |
802 | printf("uha%d: board timed out during reset\n", unit); | |
803 | return (ENXIO); | |
15637ed4 | 804 | } |
519fb2b7 RG |
805 | outb(port + UHA_SMASK, 0x81); /* make sure interrupts are enabled */ |
806 | uha->flags |= UHA_INIT; | |
807 | return (0); | |
15637ed4 RG |
808 | } |
809 | ||
15637ed4 RG |
810 | #ifndef min |
811 | #define min(x,y) (x < y ? x : y) | |
519fb2b7 | 812 | #endif /* min */ |
15637ed4 | 813 | |
519fb2b7 RG |
814 | void |
815 | uhaminphys(bp) | |
816 | struct buf *bp; | |
15637ed4 | 817 | { |
519fb2b7 RG |
818 | if (bp->b_bcount > ((UHA_NSEG - 1) * PAGESIZ)) { |
819 | bp->b_bcount = ((UHA_NSEG - 1) * PAGESIZ); | |
15637ed4 RG |
820 | } |
821 | } | |
822 | ||
519fb2b7 RG |
823 | /* |
824 | * start a scsi operation given the command and the data address. Also | |
825 | * needs the unit, target and lu. | |
826 | */ | |
827 | int32 | |
828 | uha_scsi_cmd(xs) | |
829 | struct scsi_xfer *xs; | |
15637ed4 | 830 | { |
519fb2b7 RG |
831 | struct scsi_sense_data *s1, *s2; |
832 | struct mscp *mscp; | |
833 | struct uha_dma_seg *sg; | |
834 | int seg; /* scatter gather seg being worked on */ | |
835 | int i = 0; | |
836 | int rc = 0; | |
15637ed4 | 837 | int thiskv; |
519fb2b7 RG |
838 | unsigned long int thisphys, nextphys; |
839 | int unit = xs->sc_link->adapter_unit; | |
840 | int bytes_this_seg, bytes_this_page, datalen, flags; | |
841 | struct iovec *iovp; | |
842 | struct uha_data *uha = uhadata[unit]; | |
15637ed4 RG |
843 | int s; |
844 | unsigned int stat; | |
519fb2b7 | 845 | int port = uha->baseport; |
15637ed4 RG |
846 | unsigned long int templen; |
847 | ||
519fb2b7 RG |
848 | SC_DEBUG(xs->sc_link, SDEV_DB2, ("uha_scsi_cmd\n")); |
849 | /* | |
850 | * get a mscp (mbox-out) to use. If the transfer | |
851 | * is from a buf (possibly from interrupt time) | |
852 | * then we can't allow it to sleep | |
853 | */ | |
15637ed4 | 854 | flags = xs->flags; |
519fb2b7 RG |
855 | if (xs->bp) |
856 | flags |= (SCSI_NOSLEEP); /* just to be sure */ | |
857 | if (flags & ITSDONE) { | |
858 | printf("uha%d: Already done?", unit); | |
15637ed4 RG |
859 | xs->flags &= ~ITSDONE; |
860 | } | |
519fb2b7 RG |
861 | if (!(flags & INUSE)) { |
862 | printf("uha%d: Not in use?", unit); | |
15637ed4 RG |
863 | xs->flags |= INUSE; |
864 | } | |
519fb2b7 | 865 | if (!(mscp = uha_get_mscp(unit, flags))) { |
15637ed4 | 866 | xs->error = XS_DRIVER_STUFFUP; |
519fb2b7 | 867 | return (TRY_AGAIN_LATER); |
15637ed4 | 868 | } |
519fb2b7 RG |
869 | cheat = mscp; |
870 | SC_DEBUG(xs->sc_link, SDEV_DB3, ("start mscp(%x)\n", mscp)); | |
15637ed4 | 871 | mscp->xs = xs; |
15637ed4 | 872 | |
519fb2b7 RG |
873 | /* |
874 | * Put all the arguments for the xfer in the mscp | |
875 | */ | |
876 | if (flags & SCSI_RESET) { | |
15637ed4 RG |
877 | mscp->opcode = 0x04; |
878 | mscp->ca = 0x01; | |
519fb2b7 | 879 | } else { |
15637ed4 RG |
880 | mscp->opcode = 0x02; |
881 | mscp->ca = 0x01; | |
519fb2b7 RG |
882 | } |
883 | if (flags & SCSI_DATA_IN) { | |
15637ed4 RG |
884 | mscp->xdir = 0x01; |
885 | } | |
519fb2b7 | 886 | if (flags & SCSI_DATA_OUT) { |
15637ed4 RG |
887 | mscp->xdir = 0x02; |
888 | } | |
519fb2b7 RG |
889 | #ifdef GOTTABEJOKING |
890 | if (xs->sc_link->lun != 0) { | |
15637ed4 | 891 | xs->error = XS_DRIVER_STUFFUP; |
519fb2b7 RG |
892 | uha_free_mscp(unit, mscp, flags); |
893 | return (HAD_ERROR); | |
15637ed4 | 894 | } |
519fb2b7 RG |
895 | #endif |
896 | mscp->dcn = 0x00; | |
897 | mscp->chan = 0x00; | |
898 | mscp->target = xs->sc_link->target; | |
899 | mscp->lun = xs->sc_link->lun; | |
900 | mscp->link.addr[0] = 0x00; | |
901 | mscp->link.addr[1] = 0x00; | |
902 | mscp->link.addr[2] = 0x00; | |
903 | mscp->link.addr[3] = 0x00; | |
904 | mscp->link_id = 0x00; | |
905 | mscp->cdblen = xs->cmdlen; | |
906 | scratch = KVTOPHYS(&(mscp->mscp_sense)); | |
907 | mscp->sense.addr[0] = (scratch & 0xff); | |
908 | mscp->sense.addr[1] = ((scratch >> 8) & 0xff); | |
909 | mscp->sense.addr[2] = ((scratch >> 16) & 0xff); | |
910 | mscp->sense.addr[3] = ((scratch >> 24) & 0xff); | |
911 | mscp->senselen = sizeof(mscp->mscp_sense); | |
912 | mscp->ha_status = 0x00; | |
913 | mscp->targ_status = 0x00; | |
914 | ||
915 | if (xs->datalen) { /* should use S/G only if not zero length */ | |
916 | scratch = KVTOPHYS(mscp->uha_dma); | |
917 | mscp->data.addr[0] = (scratch & 0xff); | |
918 | mscp->data.addr[1] = ((scratch >> 8) & 0xff); | |
919 | mscp->data.addr[2] = ((scratch >> 16) & 0xff); | |
920 | mscp->data.addr[3] = ((scratch >> 24) & 0xff); | |
921 | sg = mscp->uha_dma; | |
922 | seg = 0; | |
923 | mscp->sgth = 0x01; | |
924 | ||
925 | #ifdef TFS | |
926 | if (flags & SCSI_DATA_UIO) { | |
927 | iovp = ((struct uio *) xs->data)->uio_iov; | |
928 | datalen = ((struct uio *) xs->data)->uio_iovcnt; | |
15637ed4 | 929 | xs->datalen = 0; |
519fb2b7 RG |
930 | while ((datalen) && (seg < UHA_NSEG)) { |
931 | scratch = (unsigned long) iovp->iov_base; | |
932 | sg->addr.addr[0] = (scratch & 0xff); | |
15637ed4 RG |
933 | sg->addr.addr[1] = ((scratch >> 8) & 0xff); |
934 | sg->addr.addr[2] = ((scratch >> 16) & 0xff); | |
935 | sg->addr.addr[3] = ((scratch >> 24) & 0xff); | |
519fb2b7 RG |
936 | xs->datalen += *(unsigned long *) sg->len.len = iovp->iov_len; |
937 | SC_DEBUGN(xs->sc_link, SDEV_DB4, ("(0x%x@0x%x)", | |
938 | iovp->iov_len, | |
939 | iovp->iov_base)); | |
15637ed4 RG |
940 | sg++; |
941 | iovp++; | |
942 | seg++; | |
943 | datalen--; | |
944 | } | |
519fb2b7 RG |
945 | } else |
946 | #endif /*TFS */ | |
15637ed4 | 947 | { |
519fb2b7 RG |
948 | /* |
949 | * Set up the scatter gather block | |
950 | */ | |
951 | ||
952 | SC_DEBUG(xs->sc_link, SDEV_DB4, | |
953 | ("%d @0x%x:- ", xs->datalen, xs->data)); | |
954 | datalen = xs->datalen; | |
955 | thiskv = (int) xs->data; | |
956 | thisphys = KVTOPHYS(thiskv); | |
957 | templen = 0; | |
958 | ||
959 | while ((datalen) && (seg < UHA_NSEG)) { | |
960 | bytes_this_seg = 0; | |
961 | ||
15637ed4 RG |
962 | /* put in the base address */ |
963 | sg->addr.addr[0] = (thisphys & 0xff); | |
964 | sg->addr.addr[1] = ((thisphys >> 8) & 0xff); | |
965 | sg->addr.addr[2] = ((thisphys >> 16) & 0xff); | |
966 | sg->addr.addr[3] = ((thisphys >> 24) & 0xff); | |
519fb2b7 RG |
967 | |
968 | SC_DEBUGN(xs->sc_link, SDEV_DB4, ("0x%x", thisphys)); | |
969 | ||
15637ed4 | 970 | /* do it at least once */ |
519fb2b7 | 971 | nextphys = thisphys; |
15637ed4 | 972 | while ((datalen) && (thisphys == nextphys)) |
519fb2b7 RG |
973 | /* |
974 | * This page is contiguous (physically) with | |
975 | * the the last, just extend the length | |
976 | */ | |
15637ed4 RG |
977 | { |
978 | /* how far to the end of the page */ | |
979 | nextphys = (thisphys & (~(PAGESIZ - 1))) | |
519fb2b7 | 980 | + PAGESIZ; |
15637ed4 RG |
981 | bytes_this_page = nextphys - thisphys; |
982 | /**** or the data ****/ | |
983 | bytes_this_page = min(bytes_this_page | |
519fb2b7 RG |
984 | ,datalen); |
985 | bytes_this_seg += bytes_this_page; | |
986 | datalen -= bytes_this_page; | |
987 | ||
15637ed4 | 988 | /* get more ready for the next page */ |
519fb2b7 RG |
989 | thiskv = (thiskv & (~(PAGESIZ - 1))) |
990 | + PAGESIZ; | |
991 | if (datalen) | |
15637ed4 RG |
992 | thisphys = KVTOPHYS(thiskv); |
993 | } | |
519fb2b7 RG |
994 | /* |
995 | * next page isn't contiguous, finish the seg | |
996 | */ | |
997 | SC_DEBUGN(xs->sc_link, SDEV_DB4, | |
998 | ("(0x%x)", bytes_this_seg)); | |
15637ed4 RG |
999 | sg->len.len[0] = (bytes_this_seg & 0xff); |
1000 | sg->len.len[1] = ((bytes_this_seg >> 8) & 0xff); | |
1001 | sg->len.len[2] = ((bytes_this_seg >> 16) & 0xff); | |
1002 | sg->len.len[3] = ((bytes_this_seg >> 24) & 0xff); | |
1003 | templen += bytes_this_seg; | |
1004 | sg++; | |
1005 | seg++; | |
1006 | } | |
519fb2b7 RG |
1007 | } |
1008 | ||
1009 | /* end of iov/kv decision */ | |
15637ed4 RG |
1010 | mscp->datalen.len[0] = (templen & 0xff); |
1011 | mscp->datalen.len[1] = ((templen >> 8) & 0xff); | |
1012 | mscp->datalen.len[2] = ((templen >> 16) & 0xff); | |
1013 | mscp->datalen.len[3] = ((templen >> 24) & 0xff); | |
1014 | mscp->sg_num = seg; | |
1015 | ||
519fb2b7 RG |
1016 | SC_DEBUGN(xs->sc_link, SDEV_DB4, ("\n")); |
1017 | if (datalen) { /* there's still data, must have run out of segs! */ | |
98639498 | 1018 | printf("uha%d: uha_scsi_cmd, more than %d DMA segs\n", |
519fb2b7 | 1019 | unit, UHA_NSEG); |
15637ed4 | 1020 | xs->error = XS_DRIVER_STUFFUP; |
519fb2b7 RG |
1021 | uha_free_mscp(unit, mscp, flags); |
1022 | return (HAD_ERROR); | |
15637ed4 | 1023 | } |
519fb2b7 | 1024 | } else { /* No data xfer, use non S/G values */ |
15637ed4 RG |
1025 | mscp->data.addr[0] = 0x00; |
1026 | mscp->data.addr[1] = 0x00; | |
1027 | mscp->data.addr[2] = 0x00; | |
1028 | mscp->data.addr[3] = 0x00; | |
1029 | mscp->datalen.len[0] = 0x00; | |
1030 | mscp->datalen.len[1] = 0x00; | |
1031 | mscp->datalen.len[2] = 0x00; | |
1032 | mscp->datalen.len[3] = 0x00; | |
1033 | mscp->xdir = 0x03; | |
1034 | mscp->sgth = 0x00; | |
519fb2b7 | 1035 | mscp->sg_num = 0x00; |
15637ed4 RG |
1036 | } |
1037 | ||
519fb2b7 RG |
1038 | /* |
1039 | * Put the scsi command in the mscp and start it | |
1040 | */ | |
1041 | bcopy(xs->cmd, mscp->cdb, xs->cmdlen); | |
15637ed4 | 1042 | |
519fb2b7 RG |
1043 | /* |
1044 | * Usually return SUCCESSFULLY QUEUED | |
1045 | */ | |
1046 | if (!(flags & SCSI_NOMASK)) { | |
15637ed4 | 1047 | s = splbio(); |
519fb2b7 | 1048 | uha_send_mbox(unit, mscp); |
4c45483e | 1049 | timeout(uha_timeout, (caddr_t)mscp, (xs->timeout * hz) / 1000); |
15637ed4 | 1050 | splx(s); |
519fb2b7 RG |
1051 | SC_DEBUG(xs->sc_link, SDEV_DB3, ("cmd_sent\n")); |
1052 | return (SUCCESSFULLY_QUEUED); | |
15637ed4 | 1053 | } |
519fb2b7 RG |
1054 | |
1055 | /* | |
1056 | * If we can't use interrupts, poll on completion | |
1057 | */ | |
1058 | uha_send_mbox(unit, mscp); | |
1059 | SC_DEBUG(xs->sc_link, SDEV_DB3, ("cmd_wait\n")); | |
1060 | do { | |
1061 | if (uha_poll(unit, xs->timeout)) { | |
98639498 | 1062 | if (!(xs->flags & SCSI_SILENT)) |
519fb2b7 RG |
1063 | printf("uha%d: cmd fail\n", unit); |
1064 | if (!(uha_abort(unit, mscp))) { | |
1065 | printf("uha%d: abort failed in wait\n", unit); | |
1066 | uha_free_mscp(unit, mscp, flags); | |
15637ed4 RG |
1067 | } |
1068 | xs->error = XS_DRIVER_STUFFUP; | |
519fb2b7 | 1069 | return (HAD_ERROR); |
15637ed4 | 1070 | } |
15637ed4 | 1071 | } |
519fb2b7 RG |
1072 | while (!(xs->flags & ITSDONE)); /* something (?) else finished */ |
1073 | if (xs->error) { | |
1074 | return (HAD_ERROR); | |
1075 | } | |
1076 | return (COMPLETE); | |
15637ed4 RG |
1077 | } |
1078 | ||
519fb2b7 | 1079 | void |
4c45483e | 1080 | uha_timeout(caddr_t arg1, int arg2) |
15637ed4 | 1081 | { |
4c45483e | 1082 | struct mscp *mscp = (struct mscp *)arg1; |
15637ed4 | 1083 | int unit; |
519fb2b7 RG |
1084 | struct uha_data *uha; |
1085 | int s = splbio(); | |
1086 | /*int port = uha->baseport; */ | |
1087 | ||
1088 | unit = mscp->xs->sc_link->adapter_unit; | |
1089 | uha = uhadata[unit]; | |
1090 | printf("uha%d:%d:%d (%s%d) timed out ", unit | |
1091 | ,mscp->xs->sc_link->target | |
1092 | ,mscp->xs->sc_link->lun | |
1093 | ,mscp->xs->sc_link->device->name | |
1094 | ,mscp->xs->sc_link->dev_unit); | |
15637ed4 | 1095 | |
b33502d5 | 1096 | #ifdef UHADEBUG |
519fb2b7 RG |
1097 | uha_print_active_mscp(unit); |
1098 | #endif /*UHADEBUG */ | |
b33502d5 | 1099 | |
519fb2b7 | 1100 | if ((uha_abort(unit, mscp) != 1) || (mscp->flags = MSCP_ABORTED)) { |
b33502d5 | 1101 | printf("AGAIN"); |
519fb2b7 RG |
1102 | mscp->xs->retries = 0; /* I MEAN IT ! */ |
1103 | uha_done(unit, mscp, FAIL); | |
1104 | } else { /* abort the operation that has timed out */ | |
b33502d5 | 1105 | printf("\n"); |
4c45483e | 1106 | timeout(uha_timeout, (caddr_t)mscp, 2 * hz); |
b33502d5 | 1107 | mscp->flags = MSCP_ABORTED; |
15637ed4 RG |
1108 | } |
1109 | splx(s); | |
15637ed4 RG |
1110 | } |
1111 | ||
519fb2b7 RG |
1112 | #ifdef UHADEBUG |
1113 | void | |
15637ed4 | 1114 | uha_print_mscp(mscp) |
519fb2b7 | 1115 | struct mscp *mscp; |
15637ed4 RG |
1116 | { |
1117 | printf("mscp:%x op:%x cmdlen:%d senlen:%d\n" | |
519fb2b7 RG |
1118 | ,mscp |
1119 | ,mscp->opcode | |
1120 | ,mscp->cdblen | |
1121 | ,mscp->senselen); | |
b33502d5 | 1122 | printf(" sg:%d sgnum:%x datlen:%d hstat:%x tstat:%x flags:%x\n" |
519fb2b7 RG |
1123 | ,mscp->sgth |
1124 | ,mscp->sg_num | |
1125 | ,mscp->datalen | |
1126 | ,mscp->ha_status | |
1127 | ,mscp->targ_status | |
1128 | ,mscp->flags); | |
1129 | show_scsi_cmd(mscp->xs); | |
15637ed4 RG |
1130 | } |
1131 | ||
519fb2b7 | 1132 | void |
b33502d5 | 1133 | uha_print_active_mscp(int unit) |
15637ed4 | 1134 | { |
519fb2b7 RG |
1135 | struct uha_data *uha = uhadata[unit]; |
1136 | struct mscp *mscp; | |
1137 | int i = 0; | |
15637ed4 | 1138 | |
519fb2b7 RG |
1139 | while (i < MSCP_HASH_SIZE) { |
1140 | mscp = uha->mscphash[i]; | |
1141 | while (mscp) { | |
1142 | if (mscp->flags != MSCP_FREE) { | |
1143 | uha_print_mscp(mscp); | |
1144 | } | |
1145 | mscp = mscp->nexthash; | |
1146 | } | |
1147 | i++; | |
15637ed4 | 1148 | } |
15637ed4 | 1149 | } |
519fb2b7 RG |
1150 | #endif /*UHADEBUG */ |
1151 | #endif /*KERNEL */ |