added my responsibility for the `cpm' port
[unix-history] / sys / i386 / isa / ultra14f.c
CommitLineData
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
53typedef struct {
54 unsigned char addr[4];
55} physaddr;
56typedef 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
72extern 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
177struct uha_dma_seg {
178 physaddr addr;
179 physlen len;
15637ed4 180};
15637ed4 181
519fb2b7
RG
182struct 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 224struct 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
237int uhaprobe();
238int uha_attach();
239int uhaintr();
519fb2b7 240int32 uha_scsi_cmd();
4c45483e 241void uha_timeout(caddr_t, int);
519fb2b7
RG
242void uha_free_mscp();
243int uha_abort();
15637ed4 244void uhaminphys();
519fb2b7
RG
245void uha_done();
246u_int32 uha_adapter_info();
247struct mscp *uha_mscp_phys_kv();
15637ed4 248
519fb2b7 249struct mscp *cheat;
15637ed4 250unsigned long int scratch;
519fb2b7 251static 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
261struct isa_driver uhadriver =
262{
263 uhaprobe,
264 uha_attach,
265 "uha"
266};
267
268struct 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 */
280struct 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
294main()
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 */
304void
305uha_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 */
329int
330uha_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 */
375int
376uha_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 */
401int
15637ed4 402uhaprobe(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 */
454int
15637ed4 455uha_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 */
482u_int32
483uha_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 */
492int
15637ed4 493uhaintr(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 */
539void
540uha_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 */
610void
611uha_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 642struct mscp *
519fb2b7
RG
643uha_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 */
699struct mscp *
700uha_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 */
718int
15637ed4 719uha_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
814void
815uhaminphys(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 */
827int32
828uha_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 1079void
4c45483e 1080uha_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
1113void
15637ed4 1114uha_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 1132void
b33502d5 1133uha_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 */