Commit | Line | Data |
---|---|---|
d7e75661 SV |
1 | /* |
2 | * (Free/Net/386)BSD ST01/02, Future Domain TMC-885, TMC-950 SCSI driver for | |
3 | * Julians SCSI-code | |
4 | * | |
5 | * Copyright 1994, Kent Palmkvist (kentp@isy.liu.se) | |
6 | * Copyright 1994, Robert Knier (rknier@qgraph.com) | |
7 | * Copyright 1992, 1994 Drew Eckhardt (drew@colorado.edu) | |
8 | * Copyright 1994, Julian Elischer (julian@tfs.com) | |
9 | * | |
10 | * Others that has contributed by example code is | |
11 | * Glen Overby (overby@cray.com) | |
12 | * Tatu Yllnen | |
13 | * Brian E Litzinger | |
14 | * | |
15 | * Redistribution and use in source and binary forms, with or without | |
16 | * modification, are permitted provided that the following conditions | |
17 | * are met: | |
18 | * 1. Redistributions of source code must retain the above copyright | |
19 | * notice, this list of conditions and the following disclaimer. | |
20 | * 2. Redistributions in binary form must reproduce the above copyright | |
21 | * notice, this list of conditions and the following disclaimer in the | |
22 | * documentation and/or other materials provided with the distribution. | |
23 | * | |
24 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND | |
25 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
26 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
27 | * ARE DISCLAIMED. IN NO EVENT SHALL THE DEVELOPERS BE LIABLE | |
28 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
29 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
30 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
31 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
32 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
33 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
34 | * SUCH DAMAGE. | |
35 | */ | |
36 | ||
37 | /* | |
38 | * | |
39 | * kentp 940307 alpha version based on newscsi-03 version of Julians SCSI-code | |
40 | * kentp 940314 Added possibility to not use messages | |
41 | * rknier 940331 Added fast transfer code | |
42 | * rknier 940407 Added assembler coded data transfers | |
43 | * | |
027af0d8 | 44 | * $Id: seagate.c,v 1.2 1994/06/13 02:49:12 sean Exp $ |
d7e75661 SV |
45 | */ |
46 | ||
47 | /* | |
48 | * What should really be done: | |
49 | * | |
50 | * Add missing tests for timeouts | |
51 | * Restructure interrupt enable/disable code (runs to long with int disabled) | |
52 | * Find bug? giving problem with tape status | |
53 | * Add code to handle Future Domain 840, 841, 880 and 881 | |
54 | * adjust timeouts (startup is very slow) | |
55 | * add code to use tagged commands in SCSI2 | |
56 | * Add code to handle slow devices better (sleep if device not disconnecting) | |
57 | * Fix unnecessary interrupts | |
58 | */ | |
59 | ||
60 | /* Note to users trying to share a disk between DOS and unix: | |
61 | * The ST01/02 is a translating host-adapter. It is not giving DOS | |
62 | * the same number of heads/tracks/sectors as specified by the disk. | |
63 | * It is therefore important to look at what numbers DOS thinks the | |
64 | * disk has. Use these to disklabel your disk in an appropriate manner | |
65 | */ | |
66 | ||
67 | #include <sys/types.h> | |
68 | ||
69 | #ifdef KERNEL /* don't laugh.. look for main() */ | |
70 | #include <sea.h> | |
71 | ||
72 | #include <sys/param.h> | |
73 | #include <sys/systm.h> | |
74 | #include <sys/errno.h> | |
75 | #include <sys/ioctl.h> | |
76 | #include <sys/malloc.h> | |
77 | #include <sys/buf.h> | |
78 | #include <sys/proc.h> | |
79 | #include <sys/user.h> | |
80 | #include <i386/isa/isa_device.h> | |
81 | #endif /* KERNEL */ | |
82 | #include <scsi/scsi_all.h> | |
83 | #include <scsi/scsiconf.h> | |
84 | ||
85 | #ifdef KERNEL | |
86 | #include "ddb.h" | |
87 | #include "kernel.h" | |
88 | #else /* KERNEL */ | |
89 | #define NSEA 1 | |
90 | #endif /* KERNEL */ | |
91 | ||
92 | extern int hz; | |
93 | ||
94 | #define SEA_SCB_MAX 8 /* allow maximally 8 scsi control blocks */ | |
95 | #define SCB_TABLE_SIZE 8 /* start with 8 scb entries in table */ | |
96 | #define BLOCK_SIZE 512 /* size of READ/WRITE areas on SCSI card */ | |
97 | ||
98 | /* | |
99 | * defining PARITY causes parity data to be checked | |
100 | */ | |
101 | #define PARITY 1 | |
102 | ||
103 | /* | |
104 | * defining SEA_BLINDTRANSFER will make DATA IN and DATA OUT to be done with | |
105 | * blind transfers, i.e. no check is done for scsi phase changes. This will | |
106 | * result in data loss if the scsi device does not send its data using | |
107 | * BLOCK_SIZE bytes at a time. | |
108 | * If SEA_BLINDTRANSFER defined and SEA_ASSEMBLER also defined will result in | |
109 | * the use of blind transfers coded in assembler. SEA_ASSEMBLER is no good | |
110 | * without SEA_BLINDTRANSFER defined. | |
111 | */ | |
112 | #define SEA_BLINDTRANSFER 1 /* do blind transfers */ | |
113 | #define SEA_ASSEMBLER 1 /* Use assembly code for fast transfers */ | |
114 | ||
115 | /* | |
116 | * defining SEANOMSGS causes messages not to be used (thereby disabling | |
117 | * disconnects) | |
118 | */ | |
119 | /* #define SEANOMSGS 1 */ | |
120 | ||
121 | /* | |
122 | * defining SEA_NODATAOUT makes dataout phase being aborted | |
123 | */ | |
124 | /* #define SEA_NODATAOUT 1 */ | |
125 | ||
126 | /* | |
127 | * defining SEA_SENSEFIRST make REQUEST_SENSE opcode to be placed first | |
128 | */ | |
129 | /* #define SEA_SENSEFIRST 1 */ | |
130 | ||
131 | #define SEA_FREEBSD11 1 /* intermediate def. for FreeBSD 1.1 BETA */ | |
132 | /* timeout function has changed */ | |
133 | ||
134 | /* Debugging definitions. Should not be used unless you want a lot of | |
135 | printouts even under normal conditions */ | |
136 | ||
137 | /* #define SEADEBUG 1 */ /* General info about errors */ | |
138 | /* #define SEADEBUG1 1 */ /* Info about internal results and errors */ | |
139 | /* #define SEADEBUG2 1 */ /* Display a lot about timeouts etc */ | |
140 | /* #define SEADEBUG3 1 */ | |
141 | /* #define SEADEBUG4 1 */ | |
142 | /* #define SEADEBUG5 1 */ | |
143 | /* #define SEADEBUG6 1 */ /* Display info about queue-lengths */ | |
144 | /* #define SEADEBUG7 1 */ /* Extra check on STATUS before phase check */ | |
145 | /* #define SEADEBUG8 1 */ /* Disregard non-BSY state in | |
146 | sea_information_transfer */ | |
147 | /* #define SEADEBUG9 1 */ /* Enable printouts */ | |
148 | /* #define SEADEBUG11 1 */ /* stop everything except access to scsi id 1 */ | |
149 | /* #define SEADEBUG15 1 */ /* Display every byte sent/received */ | |
150 | ||
151 | #define NUM_CONCURRENT 1 /* number of concurrent ops per board */ | |
152 | ||
153 | /******************************* board definitions **************************/ | |
154 | /* | |
155 | * CONTROL defines | |
156 | */ | |
157 | ||
158 | #define CMD_RST 0x01 /* scsi reset */ | |
159 | #define CMD_SEL 0x02 /* scsi select */ | |
160 | #define CMD_BSY 0x04 /* scsi busy */ | |
161 | #define CMD_ATTN 0x08 /* scsi attention */ | |
162 | #define CMD_START_ARB 0x10 /* start arbitration bit */ | |
163 | #define CMD_EN_PARITY 0x20 /* enable scsi parity generation */ | |
164 | #define CMD_INTR 0x40 /* enable scsi interrupts */ | |
165 | #define CMD_DRVR_ENABLE 0x80 /* scsi enable */ | |
166 | ||
167 | /* | |
168 | * STATUS | |
169 | */ | |
170 | ||
171 | #define STAT_BSY 0x01 /* scsi busy */ | |
172 | #define STAT_MSG 0x02 /* scsi msg */ | |
173 | #define STAT_IO 0x04 /* scsi I/O */ | |
174 | #define STAT_CD 0x08 /* scsi C/D */ | |
175 | #define STAT_REQ 0x10 /* scsi req */ | |
176 | #define STAT_SEL 0x20 /* scsi select */ | |
177 | #define STAT_PARITY 0x40 /* parity error bit */ | |
178 | #define STAT_ARB_CMPL 0x80 /* arbitration complete bit */ | |
179 | ||
180 | /* | |
181 | * REQUESTS | |
182 | */ | |
183 | ||
184 | #define REQ_MASK (STAT_CD | STAT_IO | STAT_MSG) | |
185 | #define REQ_DATAOUT 0 | |
186 | #define REQ_DATAIN STAT_IO | |
187 | #define REQ_CMDOUT STAT_CD | |
188 | #define REQ_STATIN (STAT_CD | STAT_IO) | |
189 | #define REQ_MSGOUT (STAT_MSG | STAT_CD) | |
190 | #define REQ_MSGIN (STAT_MSG | STAT_CD | STAT_IO) | |
191 | ||
192 | #define REQ_UNKNOWN 0xff | |
193 | ||
194 | #define SEAGATERAMOFFSET 0x00001800 | |
195 | ||
196 | #ifdef PARITY | |
197 | #define BASE_CMD (CMD_EN_PARITY | CMD_INTR) | |
198 | #else | |
199 | #define BASE_CMD (CMD_INTR) | |
200 | #endif | |
201 | ||
202 | #define SEAGATE 1 | |
203 | #define FD 2 | |
204 | ||
205 | /****************************************************************************** | |
206 | * This should be placed in a more generic file (presume in /sys/scsi) | |
207 | * Message codes: | |
208 | */ | |
209 | #define MSG_ABORT 0x06 | |
210 | #define MSG_NOP 0x08 | |
211 | #define MSG_COMMAND_COMPLETE 0x00 | |
212 | #define MSG_DISCONNECT 0x04 | |
213 | #define MSG_IDENTIFY 0x80 | |
214 | #define MSG_BUS_DEV_RESET 0x0c | |
215 | #define MSG_MESSAGE_REJECT 0x07 | |
216 | #define MSG_SAVE_POINTERS 0x02 | |
217 | #define MSG_RESTORE_POINTERS 0x03 | |
218 | /******************************************************************************/ | |
219 | ||
220 | #define IDENTIFY(can_disconnect,lun) (MSG_IDENTIFY | ((can_disconnect) ? \ | |
221 | 0x40 : 0) | ((lun) & 0x07)) | |
222 | ||
223 | /* scsi control block used to keep info about a scsi command */ | |
224 | struct sea_scb | |
225 | { | |
226 | int flags; /* status of the instruction */ | |
227 | #define SCB_FREE 0 | |
228 | #define SCB_ACTIVE 1 | |
229 | #define SCB_ABORTED 2 | |
230 | #define SCB_TIMEOUT 4 | |
231 | #define SCB_ERROR 8 | |
232 | #define SCB_TIMECHK 16 /* We have set a timeout on this one */ | |
233 | struct sea_scb *next; /* in free list */ | |
234 | struct scsi_xfer *xfer; /* the scsi_xfer for this cmd */ | |
235 | u_char * data; /* position in data buffer so far */ | |
236 | int32 datalen; /* bytes remaining to transfer */; | |
237 | }; | |
238 | ||
239 | /* | |
240 | * data structure describing current status of the scsi bus. One for each | |
241 | * controller card. | |
242 | */ | |
243 | struct sea_data | |
244 | { | |
245 | caddr_t basemaddr; /* Base address for card */ | |
246 | char ctrl_type; /* FD or SEAGATE */ | |
247 | caddr_t st0x_cr_sr; /* Address of control and status register */ | |
248 | caddr_t st0x_dr; /* Address of data register */ | |
249 | u_short vect; /* interrupt vector for this card */ | |
250 | int our_id; /* our scsi id */ | |
251 | int numscb; /* number of scsi control blocks */ | |
252 | struct scsi_link sc_link; /* struct connecting different data */ | |
253 | struct sea_scb *connected; /* currently connected command */ | |
254 | struct sea_scb *issue_queue; /* waiting to be issued */ | |
255 | struct sea_scb *disconnected_queue; /* waiting to reconnect */ | |
256 | struct sea_scb scbs[SCB_TABLE_SIZE]; | |
257 | struct sea_scb *free_scb; /* free scb list */ | |
258 | volatile unsigned char busy[8]; /* index=target, bit=lun, Keep track of | |
259 | busy luns at device target */ | |
260 | } *seadata[NSEA]; | |
261 | ||
262 | /* flag showing if main routine is running. */ | |
263 | static volatile int main_running = 0; | |
264 | ||
265 | #define STATUS (*(volatile unsigned char *) sea->st0x_cr_sr) | |
266 | #define CONTROL STATUS | |
267 | #define DATA (*(volatile unsigned char *) sea->st0x_dr) | |
268 | ||
269 | /* | |
270 | * These are "special" values for the tag parameter passed to sea_select | |
271 | * Not implemented right now. | |
272 | */ | |
273 | ||
274 | #define TAG_NEXT -1 /* Use next free tag */ | |
275 | #define TAG_NONE -2 /* | |
276 | * Establish I_T_L nexus instead of I_T_L_Q | |
277 | * even on SCSI-II devices. | |
278 | */ | |
279 | ||
280 | typedef struct { | |
281 | char *signature ; | |
282 | unsigned offset; | |
283 | unsigned length; | |
284 | unsigned char type; | |
285 | } BiosSignature; | |
286 | ||
287 | /* | |
288 | * Signatures for automatic recognition of board type | |
289 | */ | |
290 | ||
291 | static const BiosSignature signatures[] = { | |
292 | {"ST01 v1.7 (C) Copyright 1987 Seagate", 15, 37, SEAGATE}, | |
293 | {"SCSI BIOS 2.00 (C) Copyright 1987 Seagate", 15, 40, SEAGATE}, | |
294 | ||
295 | /* | |
296 | * The following two lines are NOT mistakes. One detects ROM revision | |
297 | * 3.0.0, the other 3.2. Since seagate has only one type of SCSI adapter, | |
298 | * and this is not going to change, the "SEAGATE" and "SCSI" together | |
299 | * are probably "good enough" | |
300 | */ | |
301 | ||
302 | {"SEAGATE SCSI BIOS ", 16, 17, SEAGATE}, | |
303 | {"SEAGATE SCSI BIOS ", 17, 17, SEAGATE}, | |
304 | ||
305 | /* | |
306 | * However, future domain makes several incompatible SCSI boards, so specific | |
307 | * signatures must be used. | |
308 | */ | |
309 | ||
310 | {"FUTURE DOMAIN CORP. (C) 1986-1989 V5.0C2/14/89", 5, 45, FD}, | |
311 | {"FUTURE DOMAIN CORP. (C) 1986-1989 V6.0A7/28/89", 5, 46, FD}, | |
312 | {"FUTURE DOMAIN CORP. (C) 1986-1990 V6.0105/31/90",5, 47, FD}, | |
313 | {"FUTURE DOMAIN CORP. (C) 1986-1990 V6.0209/18/90",5, 47, FD}, | |
314 | {"FUTURE DOMAIN CORP. (C) 1986-1990 V7.009/18/90", 5, 46, FD}, | |
315 | {"FUTURE DOMAIN CORP. (C) 1992 V8.00.004/02/92", 5, 44, FD}, | |
316 | {"FUTURE DOMAIN TMC-950", 5, 21, FD}, | |
317 | }; | |
318 | ||
319 | #define NUM_SIGNATURES (sizeof(signatures) / sizeof(BiosSignature)) | |
320 | ||
321 | static const char * seagate_bases[] = { | |
322 | (char *) 0xc8000, (char *) 0xca000, (char *) 0xcc000, | |
323 | (char *) 0xce000, (char *) 0xdc000, (char *) 0xde000 | |
324 | }; | |
325 | ||
326 | #define NUM_BASES (sizeof(seagate_bases)/sizeof(char *)) | |
327 | ||
328 | int sea_probe(struct isa_device *dev); | |
329 | int sea_attach(struct isa_device *dev); | |
330 | int seaintr(int unit); | |
331 | int32 sea_scsi_cmd(struct scsi_xfer *xs); | |
332 | #ifdef SEA_FREEBSD11 | |
333 | void sea_timeout(caddr_t, int); | |
334 | #else | |
335 | void sea_timeout(struct sea_scb *scb); | |
336 | #endif | |
337 | void seaminphys(struct buf *bp); | |
338 | void sea_done(int unit, struct sea_scb *scb); | |
339 | u_int32 sea_adapter_info(int unit); | |
340 | struct sea_scb *sea_get_scb(int unit, int flags); | |
341 | void sea_free_scb(int unit, struct sea_scb *scb, int flags); | |
342 | static void sea_main(void); | |
343 | static void sea_information_transfer(struct sea_data *sea); | |
344 | int sea_poll(int unit, struct scsi_xfer *xs, struct sea_scb *scb); | |
345 | int sea_init(int unit); | |
346 | int sea_send_scb(struct sea_data *sea, struct sea_scb *scb); | |
347 | int sea_reselect(struct sea_data *sea); | |
348 | int sea_select(struct sea_data *sea, struct sea_scb *scb); | |
349 | int sea_transfer_pio(struct sea_data *sea, u_char *phase, int32 *count, | |
350 | u_char **data); | |
351 | int sea_abort(int unit, struct sea_scb *scb); | |
352 | ||
353 | static sea_unit = 0; | |
354 | static sea_slot = -1; /* last found board seagate_bases address index */ | |
355 | #define FAIL 1 | |
356 | #define SUCCESS 0 | |
357 | ||
358 | #ifdef KERNEL | |
359 | struct scsi_adapter sea_switch = | |
360 | { | |
361 | sea_scsi_cmd, | |
362 | seaminphys, | |
363 | 0, | |
364 | 0, | |
365 | sea_adapter_info, | |
366 | "sea", | |
367 | 0,0 | |
368 | }; | |
369 | ||
370 | /* the below structure is so we have a default dev struct for our link struct */ | |
371 | struct scsi_device sea_dev = | |
372 | { | |
373 | NULL, /* use default error handler */ | |
374 | NULL, /* have a queue, served by this */ | |
375 | NULL, /* have no async handler */ | |
376 | NULL, /* Use default 'done' routine */ | |
377 | "sea", | |
378 | 0, | |
379 | 0,0 | |
380 | }; | |
381 | ||
382 | struct isa_driver seadriver = | |
383 | { | |
9b3b13e5 SV |
384 | sea_probe, |
385 | sea_attach, | |
d7e75661 SV |
386 | "sea" |
387 | }; | |
388 | ||
389 | #endif /* KERNEL */ | |
390 | ||
391 | #ifdef SEADEBUG6 | |
392 | void sea_queue_length() | |
393 | { | |
394 | struct sea_scb *tmp; | |
395 | int length = 0; | |
396 | ||
397 | if(seadata[0]->connected) | |
398 | length = 1; | |
399 | for(tmp = seadata[0]->issue_queue; tmp != NULL; tmp = tmp->next, length++); | |
400 | for(tmp = seadata[0]->disconnected_queue ; tmp != NULL; tmp->next, length++); | |
401 | printf("length:%d ",length); | |
402 | } | |
403 | #endif | |
404 | ||
405 | /***********************************************************************\ | |
406 | * Check if the device can be found at the port given and if so, detect * | |
407 | * the type of board. Set it up ready for further work. Takes the * | |
408 | * isa_dev structure from autoconf as an argument. * | |
409 | * Returns 1 if card recognized, 0 if errors * | |
410 | \***********************************************************************/ | |
411 | int | |
412 | sea_probe(dev) | |
413 | struct isa_device *dev; | |
414 | { | |
415 | int j; | |
416 | int unit = sea_unit; | |
417 | struct sea_data *sea; | |
418 | dev->id_unit = unit; | |
419 | ||
420 | #ifdef SEADEBUG2 | |
421 | printf("sea_probe "); | |
422 | #endif | |
423 | ||
424 | /* find unit and check we have that many defined */ | |
425 | if(unit >= NSEA) { | |
426 | printf("sea%d: unit number too high\n",unit); | |
427 | return(0); | |
428 | } | |
429 | dev->id_unit = unit; | |
430 | #ifdef SEADEBUG2 | |
431 | printf("unit: %d\n",unit); | |
432 | printf("dev_addr: 0x%lx\n",dev->id_maddr); | |
433 | #endif | |
434 | /* allocate a storage area for us */ | |
435 | ||
436 | if (seadata[unit]) { | |
437 | printf("sea%d: memory already allocated\n", unit); | |
438 | return(0); | |
439 | } | |
440 | #ifdef SEADEBUG2 | |
441 | printf("Before malloc\n"); | |
442 | #endif | |
443 | sea = malloc(sizeof(struct sea_data), M_TEMP, M_NOWAIT); | |
444 | if (!sea) { | |
445 | printf("sea%d: cannot malloc!\n", unit); | |
446 | return(0); | |
447 | } | |
448 | ||
449 | #ifdef SEADEBUG2 | |
450 | printf("after malloc\n"); | |
451 | for(j=0;j<32767;j++); | |
452 | #endif | |
453 | bzero(sea,sizeof(struct sea_data)); | |
454 | seadata[unit] = sea; | |
455 | ||
456 | /* check for address if no one specified */ | |
457 | sea->basemaddr = NULL; | |
458 | ||
459 | /* Could try to find a board by looking through all possible addresses */ | |
460 | /* This is not done the right way now, because I have not found a way */ | |
461 | /* to get a boards virtual memory address given its physical. There is */ | |
462 | /* a function that returns the physical address for a given virtual */ | |
463 | /* address, but not the other way around */ | |
464 | ||
465 | if(dev->id_maddr == 0) { | |
466 | /* | |
467 | for(sea_slot++;sea_slot<NUM_BASES;sea_slot++) | |
468 | for(j = 0; !sea->basemaddr && j < NUM_SIGNATURES; ++j) | |
469 | if(!memcmp((void *)(seagate_bases[sea_slot]+signatures[j].offset), | |
470 | (void *) signatures[j].signature, signatures[j].length)) { | |
471 | sea->basemaddr = (void *)seagate_bases[sea_slot]; | |
472 | break; | |
473 | } | |
474 | */ | |
475 | } else { | |
476 | ||
477 | #ifdef SEADEBUG2 | |
478 | printf("id_maddr != 0\n"); | |
479 | for(j = 0; j < 32767 ; j++); | |
480 | for(j = 0; j < 32767 ; j++); | |
481 | #endif | |
482 | /* find sea_slot position for overridden memory address */ | |
483 | for(j = 0; ((char *)vtophys(dev->id_maddr) != seagate_bases[j]) && | |
484 | j<NUM_BASES; ++j); | |
485 | if(j == NUM_BASES) { | |
486 | printf("sea: board not expected at address 0x%lx\n",dev->id_maddr); | |
487 | seadata[unit]=NULL; | |
488 | free(sea, M_TEMP); | |
489 | return(0); | |
490 | } else if(sea_slot > j) { | |
491 | printf("sea: board address 0x%lx already probed!\n", dev->id_maddr); | |
492 | seadata[unit]=NULL; | |
493 | free(sea, M_TEMP); | |
494 | return(0); | |
495 | } else { | |
496 | sea->basemaddr = dev->id_maddr; | |
497 | } | |
498 | ||
499 | } | |
500 | #ifdef SEADEBUG2 | |
501 | printf("sea->basemaddr = %lx\n", sea->basemaddr); | |
502 | #endif | |
503 | ||
504 | /* check board type */ /* No way to define this through config */ | |
505 | for(j = 0; j < NUM_SIGNATURES; j++) | |
506 | if(!memcmp((void *) (sea->basemaddr + signatures[j].offset), | |
507 | (void *) signatures[j].signature, signatures[j].length)) { | |
508 | sea->ctrl_type = signatures[j].type; | |
509 | break; | |
510 | } | |
511 | if(j == NUM_SIGNATURES) { | |
512 | printf("sea: Board type unknown at address 0x%lx\n", | |
513 | sea->basemaddr); | |
514 | seadata[unit]=NULL; | |
515 | free(sea, M_TEMP); | |
516 | return(0); | |
517 | } | |
518 | ||
519 | /* Find controller and data memory addresses */ | |
520 | sea->st0x_cr_sr = (void *) (((unsigned char *) sea->basemaddr) + | |
521 | ((sea->ctrl_type == SEAGATE) ? 0x1a00 : 0x1c00)); | |
522 | sea->st0x_dr = (void *) (((unsigned char *) sea->basemaddr) + | |
523 | ((sea->ctrl_type == SEAGATE) ? 0x1c00 : 0x1e00)); | |
524 | ||
525 | /* Test controller RAM (works the same way on future domain cards?) */ | |
526 | *(sea->basemaddr + SEAGATERAMOFFSET) = 0xa5; | |
527 | *(sea->basemaddr + SEAGATERAMOFFSET + 1) = 0x5a; | |
528 | ||
529 | if((*(sea->basemaddr + SEAGATERAMOFFSET) != (char) 0xa5) || | |
530 | (*(sea->basemaddr + SEAGATERAMOFFSET + 1) != (char) 0x5a)) { | |
531 | printf("sea%d: Board RAM failure\n",unit); | |
532 | } | |
533 | ||
534 | if(sea_init(unit) != 0) { | |
535 | seadata[unit] = NULL; | |
536 | free(sea,M_TEMP); | |
537 | return(0); | |
538 | } | |
539 | ||
540 | /* if its there put in it's interrupt vector */ | |
541 | /* (Doesn't use dma, so no drq is set) */ | |
542 | sea->vect = dev->id_irq; | |
543 | ||
544 | sea_unit++; | |
545 | return(1); | |
546 | } | |
547 | ||
548 | /***********************************************\ | |
549 | * Attach all sub-devices we can find * | |
550 | \***********************************************/ | |
551 | int | |
552 | sea_attach(dev) | |
553 | struct isa_device *dev; | |
554 | { | |
555 | int unit = dev->id_unit; | |
556 | struct sea_data *sea = seadata[unit]; | |
557 | ||
558 | #ifdef SEADEBUG2 | |
559 | printf("sea_attach called\n"); | |
560 | #endif | |
561 | ||
562 | /* fill in the prototype scsi_link */ | |
563 | sea->sc_link.adapter_unit = unit; | |
564 | sea->sc_link.adapter_targ = sea->our_id; | |
565 | sea->sc_link.adapter = &sea_switch; | |
566 | sea->sc_link.device = &sea_dev; | |
567 | ||
568 | /*****************************************************\ | |
569 | * ask the adapter what subunits are present * | |
570 | \*****************************************************/ | |
571 | scsi_attachdevs(&(sea->sc_link)); | |
572 | return 1; | |
573 | } | |
574 | ||
575 | /***********************************************\ | |
576 | * Return some information to the caller about * | |
577 | * the adapter and its capabilities * | |
578 | \***********************************************/ | |
579 | u_int32 | |
580 | sea_adapter_info(unit) | |
581 | int unit; | |
582 | { | |
583 | #ifdef SEADEBUG2 | |
584 | printf("sea_adapter_info called\n"); | |
585 | #endif | |
586 | return 1; | |
587 | } | |
588 | ||
589 | /***********************************************\ | |
590 | * Catch an interrupt from the adaptor * | |
591 | \***********************************************/ | |
592 | int | |
593 | seaintr(unit) | |
594 | int unit; | |
595 | { | |
596 | int done; | |
597 | struct sea_data *sea = seadata[unit]; | |
598 | int oldpri; | |
599 | ||
600 | #if SEADEBUG2 | |
601 | printf(";"); | |
602 | #endif | |
603 | ||
604 | do { | |
605 | done = 1; | |
606 | /* dispatch to appropriate routine if found and done=0 */ | |
607 | /* should check to see that this card really caused the interrupt */ | |
608 | if ((STATUS & (STAT_SEL | STAT_IO)) == (STAT_SEL | STAT_IO)) { | |
609 | /* Reselect interrupt */ | |
610 | #ifdef SEADEBUG2 | |
611 | printf(";2"); | |
612 | #endif | |
613 | done = 0; | |
614 | /* enable_intr(); */ /* ?? How should this be done ?? */ | |
615 | sea_reselect(sea); | |
616 | } else if (STATUS & STAT_PARITY) { | |
617 | /* Parity error interrupt */ | |
618 | #ifdef SEADEBUG2 | |
619 | printf(";3"); | |
620 | #endif | |
621 | printf("sea%d: PARITY interrupt\n", unit); | |
622 | } else { | |
623 | #ifdef SEADEBUG2 | |
624 | /* printf("sea%d: unknown interrupt\n",unit); */ | |
625 | printf(";4%x", STATUS); | |
626 | #endif | |
627 | } | |
628 | if (!done) { | |
629 | oldpri = splbio(); /* disable_intr(); */ | |
630 | if (!main_running) { | |
631 | #ifdef SEADEBUG2 | |
632 | printf(";5"); | |
633 | #endif | |
634 | main_running = 1; | |
635 | sea_main(); | |
636 | /* main_running is cleared in sea_main once it can't | |
637 | * do more work, and sea_main exits with interrupts | |
638 | * disabled | |
639 | */ | |
640 | splx(oldpri); /* enable_intr(); */ | |
641 | } else { | |
642 | splx(oldpri); /* enable_intr(); */ | |
643 | } | |
644 | } | |
645 | } while (!done); | |
646 | return 1; | |
647 | } | |
648 | ||
649 | /***********************************************\ | |
650 | * Setup data structures, and reset the board * | |
651 | * and the scsi bus * | |
652 | \***********************************************/ | |
653 | int | |
654 | sea_init(unit) | |
655 | int unit; | |
656 | { | |
657 | long l; | |
658 | int i; | |
659 | struct sea_data *sea = seadata[unit]; | |
660 | ||
661 | #ifdef SEADEBUG2 | |
662 | printf("sea_init called\n"); | |
663 | #endif | |
664 | /* Reset the scsi bus (I don't know if this is needed */ | |
665 | CONTROL = BASE_CMD | CMD_DRVR_ENABLE | CMD_RST; | |
666 | DELAY(25); /* hold reset for at least 25 microseconds */ | |
667 | CONTROL = BASE_CMD; | |
668 | DELAY(10); /* wait a Bus Clear Delay (800 ns + bus free delay (800 ns) */ | |
669 | /* Set our id (don't know anything about this) */ | |
670 | if(sea->ctrl_type == SEAGATE) | |
671 | sea->our_id = 7; | |
672 | else | |
673 | sea->our_id = 6; | |
674 | /* init fields used by our routines */ | |
675 | sea->connected = NULL; | |
676 | sea->issue_queue = NULL; | |
677 | sea->disconnected_queue = NULL; | |
678 | for (i=0; i<8 ; i++) | |
679 | sea->busy[i] = 0; | |
680 | ||
681 | /* link up the free list of scbs */ | |
682 | sea->numscb = SCB_TABLE_SIZE; | |
683 | sea->free_scb = (struct sea_scb *) & (sea->scbs[0]); | |
684 | for(i=1;i< SCB_TABLE_SIZE ; i++) { | |
685 | sea->scbs[i-1].next = &(sea->scbs[i]); | |
686 | } | |
687 | sea->scbs[SCB_TABLE_SIZE - 1].next = NULL; | |
688 | ||
689 | return(0); | |
690 | } | |
691 | ||
692 | /***********************************************\ | |
693 | * * | |
694 | \***********************************************/ | |
695 | void seaminphys(bp) | |
696 | struct buf *bp; | |
697 | { | |
698 | #ifdef SEADEBUG2 | |
699 | /* printf("seaminphys called\n"); */ | |
700 | printf(","); | |
701 | #endif | |
702 | } | |
703 | ||
704 | /***********************************************\ | |
705 | * start a scsi operation given the command and * | |
706 | * the data address. Also needs the unit, target * | |
707 | * and lu * | |
708 | * get a free scb and set it up * | |
709 | * call send_scb * | |
710 | * either start timer or wait until done * | |
711 | \***********************************************/ | |
712 | int32 sea_scsi_cmd(xs) | |
713 | struct scsi_xfer *xs; | |
714 | { | |
715 | struct scsi_sense_data *s1, *s2; | |
716 | struct sea_scb *scb; | |
717 | int i = 0; | |
718 | int flags; | |
719 | int unit = xs->sc_link->adapter_unit; | |
720 | struct sea_data *sea = seadata[unit]; | |
721 | int s; | |
722 | unsigned int stat; | |
723 | int32 result; | |
724 | ||
725 | #ifdef SEADEBUG2 | |
726 | /* printf("scsi_cmd\n"); */ | |
727 | printf("="); | |
728 | #endif | |
729 | ||
730 | #ifdef SEADEBUG11 | |
731 | if(xs->sc_link->target != 1) { | |
732 | xs->flags |= ITSDONE; | |
733 | xs->error = XS_TIMEOUT; | |
734 | return(HAD_ERROR); | |
735 | } | |
736 | #endif | |
737 | ||
738 | flags = xs->flags; | |
739 | if(xs->bp) flags |= (SCSI_NOSLEEP); | |
740 | if(flags & ITSDONE) { | |
741 | printf("sea%d: Already done?", unit); | |
742 | xs->flags &= ~ITSDONE; | |
743 | } | |
744 | if(!(flags & INUSE)) { | |
745 | printf("sea%d: Not in use?", unit); | |
746 | xs->flags |= INUSE; | |
747 | } | |
748 | if (!(scb = sea_get_scb(unit, flags))) { | |
749 | #ifdef SEADEBUG2 | |
750 | printf("=2"); | |
751 | #endif | |
752 | xs->error = XS_DRIVER_STUFFUP; | |
753 | return(TRY_AGAIN_LATER); | |
754 | } | |
755 | ||
756 | /* | |
757 | * Put all the arguments for the xfer in the scb | |
758 | */ | |
759 | scb->xfer = xs; | |
760 | scb->datalen = xs->datalen; | |
761 | scb->data = xs->data; | |
762 | ||
763 | if(flags & SCSI_RESET) { | |
764 | /* Try to send a reset command to the card. This is done by calling the | |
765 | * Reset function. Should then return COMPLETE. Need to take care of the | |
766 | * possible current connected command. | |
767 | * Not implemented right now. | |
768 | */ | |
769 | printf("sea%d: Got a SCSI_RESET!\n",unit); | |
770 | } | |
771 | ||
772 | /* setup the scb to contain necessary values */ | |
773 | /* The interresting values can be read from the xs that is saved */ | |
774 | /* I therefore think that the structure can be kept very small */ | |
775 | /* the driver doesn't use DMA so the scatter/gather is not needed ? */ | |
776 | #ifdef SEADEBUG6 | |
777 | sea_queue_length(); | |
778 | #endif | |
779 | if (sea_send_scb(sea, scb) == 0) { | |
780 | #ifdef SEADEBUG2 | |
781 | printf("=3"); | |
782 | #endif | |
783 | xs->error = XS_DRIVER_STUFFUP; | |
784 | sea_free_scb(unit, scb, flags); | |
785 | return (TRY_AGAIN_LATER); | |
786 | } | |
787 | ||
788 | /* | |
789 | * Usually return SUCCESSFULLY QUEUED | |
790 | */ | |
791 | if (!(flags & SCSI_NOMASK)) { | |
792 | if(xs->flags & ITSDONE) { /* timout timer not started, already finished */ | |
793 | /* Tried to return COMPLETE but the machine hanged with this */ | |
794 | #ifdef SEADEBUG2 | |
795 | printf("=6"); | |
796 | #endif | |
797 | return(SUCCESSFULLY_QUEUED); | |
798 | } | |
799 | #ifdef SEA_FREEBSD11 | |
800 | timeout(sea_timeout, (caddr_t)scb, (xs->timeout * hz) / 1000); | |
801 | #else | |
802 | timeout(sea_timeout, scb, (xs->timeout * hz) / 1000); | |
803 | #endif | |
804 | scb->flags |= SCB_TIMECHK; | |
805 | #ifdef SEADEBUG2 | |
806 | printf("=4"); | |
807 | #endif | |
808 | return(SUCCESSFULLY_QUEUED); | |
809 | } | |
810 | ||
811 | /* | |
812 | * If we can't use interrupts, poll on completion | |
813 | */ | |
814 | ||
815 | result = sea_poll(unit, xs, scb); | |
816 | #ifdef SEADEBUG2 | |
817 | printf("=5 %lx", result); | |
818 | #endif | |
819 | return result; | |
820 | } | |
821 | ||
822 | /* | |
823 | * Get a free scb. If there are none, see if we can allocate a new one. If so, | |
824 | * put it in the hash table too, otherwise return an error or sleep. | |
825 | */ | |
826 | ||
827 | struct sea_scb * | |
828 | sea_get_scb(unit, flags) | |
829 | int unit; | |
830 | int flags; | |
831 | { | |
832 | struct sea_data *sea = seadata[unit]; | |
833 | unsigned opri = 0; | |
834 | struct sea_scb * scbp; | |
835 | int hashnum; | |
836 | ||
837 | #ifdef SEADEBUG2 | |
838 | /* printf("get_scb\n"); */ | |
839 | printf("("); | |
840 | #endif | |
841 | ||
842 | if (!(flags & SCSI_NOMASK)) | |
843 | opri = splbio(); | |
844 | ||
845 | #ifdef SEADEBUG3 | |
846 | printf("(2 %lx ", sea->free_scb); | |
847 | #endif | |
848 | ||
849 | /* | |
850 | * If we can and have to, sleep waiting for one to come free | |
851 |