xref: /haiku/src/add-ons/kernel/busses/scsi/buslogic/buslogic.c (revision 21258e2674226d6aa732321b6f8494841895af5f)
1 /*
2 ** $Id: sim_buslogic.c,v 1.8 1998/04/21 00:54:52 swetland Exp $
3 **
4 ** SCSI Interface Module for BusLogic MultiMaster Controllers
5 ** Copyright 1998, Brian J. Swetland <swetland@frotz.net>
6 **
7 ** Portions Copyright (c) 1994 by Be Incorporated.
8 ** This file may be used under the terms of the Be Sample Code License.
9 */
10 
11 
12 #include <BeBuild.h>
13 #include <iovec.h>
14 #include <KernelExport.h>
15 
16 /*
17 ** Debug options:
18 */
19 #define DEBUG_BUSLOGIC   /* Print Debugging Messages                       */
20 #define xDEBUG_TRANSACTIONS
21 #define xSERIALIZE_REQS   /* only allow one req to the controller at a time */
22 #define xVERBOSE_IRQ      /* enable kprintf()s in the IRQ handler           */
23 
24 #include <ByteOrder.h>
25 /*
26 ** Macros for virt <-> phys translation
27 */
28 #define PhysToVirt(n) ((void *) (((uint32) n) + bl->phys_to_virt))
29 #define VirtToPhys(n) (((uint32) n) + bl->virt_to_phys)
30 
31 /*
32 ** Debugging Macros
33 */
34 #ifdef DEBUG_BUSLOGIC
35 #define d_printf dprintf
36 #ifdef DEBUG_TRANSACTIONS
37 #define dt_printf dprintf
38 #else
39 #define dt_printf(x...)
40 #endif
41 #else
42 #define d_printf(x...)
43 #endif
44 
45 /* TODO:
46 **
47 ** - endian issues: the MultiMaster is little endian, should use swap()
48 **   macro for PPC compatibility whenever exchanging addresses with it (DONE)
49 ** - wrap phys addrs with ram_address()
50 ** - support scatter-gather in the ccb_scsiio struct (DONE)
51 ** - allocte bl_ccb_## semaphores on-demand (1/2 - only use 32)
52 ** - error checking for *_sem functions... we're without a net right now
53 ** - sync? (DONE - card handles this)
54 ** - tagged queuing?
55 */
56 
57 #include <OS.h>
58 #include <KernelExport.h>
59 #include <PCI.h>
60 #include <CAM.h>
61 
62 #include <stdlib.h>
63 #include <stdio.h>
64 #include <string.h>
65 
66 #include "buslogic.h"
67 
68 /*
69 ** Constants for the SIM
70 */
71 #define SIM_VERSION 0x01
72 #define HBA_VERSION 0x01
73 
74 static char sim_vendor_name[]   = "Be, Inc.";
75 static char hba_vendor_name[]   = "BusLogic";
76 static char controller_family[] = "MultiMaster PCI";
77 
78 static pci_module_info		*pci;
79 static cam_for_sim_module_info	*cam;
80 
81 static char	cam_name[] = B_CAM_FOR_SIM_MODULE_NAME;
82 static char	pci_name[] = B_PCI_MODULE_NAME;
83 
84 /*
85 ** IO Macros
86 */
87 
88 /* XXX - fix me bjs */
89 #define inb(p) (*pci->read_io_8)(p)
90 #define outb(p,v) (*pci->write_io_8)(p,v)
91 
92 #ifdef __i386__
93 #define toLE(x) (x)
94 #define unLE(x) (x)
95 #else
96 #define toLE(x) B_HOST_TO_LENDIAN_INT32(x)
97 #define unLE(x) B_LENDIAN_TO_HOST_INT32(x)
98 #endif
99 
100 
101 static int32
102 scsi_int_dispatch(void *data)
103 {
104     BusLogic *bl = (BusLogic *) data;
105     BL_CCB32 *bl_ccb;
106     uchar intstat = inb(BL_INT_REG);
107 
108 #if BOOT
109 #else
110     if(!(intstat & BL_INT_INTV)) return B_UNHANDLED_INTERRUPT;
111 #endif
112     if(intstat & BL_INT_CMDC) {
113         bl->done = 1;
114 #ifdef VERBOSE_IRQ
115         kprintf("buslogic_irq: Command Complete\n");
116 #endif
117     }
118 
119 	if(intstat & BL_INT_RSTS){
120 		kprintf("buslogic_irq: BUS RESET\n");
121 	}
122 
123         /* have we got mail? */
124     if(intstat & BL_INT_IMBL){
125         while(bl->in_boxes[bl->in_nextbox].completion_code){
126             bl_ccb = (BL_CCB32 *)
127                 PhysToVirt(unLE(bl->in_boxes[bl->in_nextbox].ccb_phys));
128 
129 #ifdef VERBOSE_IRQ
130             kprintf("buslogic_irq: CCB %08x (%08x) done, cc=0x%02x\n",
131                     unLE(bl->in_boxes[bl->in_nextbox].ccb_phys), (uint32) bl_ccb,
132                     bl->in_boxes[bl->in_nextbox].completion_code);
133 #endif
134             release_sem_etc(bl_ccb->done, 1, B_DO_NOT_RESCHEDULE);
135 
136             bl->in_boxes[bl->in_nextbox].completion_code = 0;
137             bl->in_nextbox++;
138             if(bl->in_nextbox == bl->box_count) bl->in_nextbox = 0;
139         }
140     }
141 
142         /* acknowledge the irq */
143     outb(BL_CONTROL_REG, BL_CONTROL_RINT);
144 
145     return B_HANDLED_INTERRUPT;
146 }
147 
148 
149 /* Execute a command, with optional params send (in[in_len]) and
150 ** results received (out[out_len])
151 */
152 static int bl_execute(BusLogic *bl, uchar command,
153                       void *in, int in_len,
154                       void *out, int out_len)
155 {
156     uchar status;
157     uchar *_in, *_out;
158 #ifdef TIMEOUT
159 	int timeout;
160 #endif
161 
162     _in = (uchar *) in;
163     _out = (uchar *) out;
164 
165     if(!(inb(BL_STATUS_REG) & BL_STATUS_HARDY)) {
166         d_printf("buslogic: command 0x%02x %d/%d, not ready\n",
167                  command, in_len, out_len);
168         return 1;
169     }
170 
171     outb(BL_COMMAND_REG, command);
172 
173 #ifdef TIMEOUT
174 	timeout = 100;
175 #endif
176     while(in_len){
177         status = inb(BL_STATUS_REG);
178         if(status & BL_STATUS_CMDINV) {
179             d_printf("buslogic: command 0x%02x %d/%d invalid\n",
180                      command, in_len, out_len);
181             return 1;
182         }
183         if(status & BL_STATUS_CPRBSY) {
184 #ifdef TIMEOUT
185 			timeout--;
186 			if(!timeout) {
187 				d_printf("buslogic: command 0x%02 timed out (a)\n",command);
188 				return 1;
189 			}
190 			spin(100);
191 #endif
192 			continue;
193 		}
194         outb(BL_COMMAND_REG, *_in);
195         _in++;
196         in_len--;
197     }
198 
199 #ifdef TIMEOUT
200 	timeout = 100;
201 #endif
202     while(out_len){
203         status = inb(BL_STATUS_REG);
204         if(status & BL_STATUS_CMDINV) {
205             d_printf("buslogic: command 0x%02x %d/%d invalid\n",
206                      command, in_len, out_len);
207             return 1;
208         }
209         if(status & BL_STATUS_DIRRDY) {
210             *_out = inb(BL_DATA_REG);
211             _out++;
212             out_len--;
213         } else {
214 #ifdef TIMEOUT
215 			timeout--;
216 			if(!timeout) {
217 				d_printf("buslogic: command 0x%02 timed out (b)\n",command);
218 				return 1;
219 			}
220 			spin(100);
221 #endif
222 		}
223     }
224 
225 #ifdef TIMEOUT
226 	timeout = 100;
227 #endif
228     while(!(inb(BL_STATUS_REG) & BL_STATUS_HARDY)) {
229 #ifdef TIMEOUT
230 		timeout--;
231 		if(!timeout) {
232 			d_printf("buslogic: command 0x%02 timed out (c)\n",command);
233 			return 1;
234 		}
235 		spin(100);
236 #endif
237 	}
238 
239     return 0;
240 }
241 
242 /* Initialize the BT-9X8 and confirm that it is operating as expected
243 */
244 static long init_buslogic(BusLogic *bl)
245 {
246     uchar status;
247     uchar id[16];
248     int i;
249     char *str = bl->productname;
250 
251     d_printf("buslogic: init_buslogic()\n");
252 
253     dprintf("buslogic: reset: ");
254     outb(BL_CONTROL_REG, BL_CONTROL_RHARD);
255     spin(10000); /* give the controller some time to settle down from reset */
256 
257     for(i=0;i<1000;i++){
258         spin(100000);
259         status = inb(BL_STATUS_REG);
260         if(status & BL_STATUS_DACT){
261             dprintf(".");
262             continue;
263         }
264         if(status & BL_STATUS_DFAIL){
265             dprintf(" FAILED\n");
266             return -1;
267         }
268         if(status & BL_STATUS_INREQ){
269             dprintf(" OKAY\n");
270             break;
271         }
272         if(status & BL_STATUS_HARDY) {
273             dprintf(" READY\n");
274             break;
275         }
276     }
277     if(i==100) {
278         dprintf(" TIMEOUT\n");
279         return -1;
280     }
281 
282     if(bl_execute(bl, 0x04, NULL, 0, id, 4)){
283         d_printf("buslogic: can't id?\n");
284         return B_ERROR;
285     }
286     d_printf("buslogic: Firmware Rev %c.%c\n",id[2],id[3]);
287 
288 	id[0]=14;
289 	id[14]=id[2];
290 
291 	if(bl_execute(bl, 0x8d, id, 1, id, 14)){
292 		d_printf("buslogic: cannot read extended config\n");
293 		return B_ERROR;
294 	}
295 
296 	d_printf("buslogic: rev = %c.%c%c%c mb = %d, sgmax = %d, flags = 0x%02x\n",
297 			id[14], id[10], id[11], id[12], id[4], id[2] | (id[3]<<8), id[13]);
298 	if(id[13] & 0x01) bl->wide = 1;
299 	else bl->wide = 0;
300 
301 	if(id[14] == '5'){
302 		*str++ = 'B';
303 		*str++ = 'T';
304 		*str++ = '-';
305 		*str++ = '9';
306 		*str++ = bl->wide ? '5' : '4';
307 		*str++ = '8';
308 		if(id[13] & 0x02) *str++ = 'D';
309 		*str++ = ' ';
310 		*str++ = 'v';
311 		*str++ = id[14];
312 		*str++ = '.';
313 		*str++ = id[10];
314 		*str++ = id[11];
315 		*str++ = id[12];
316 		*str++ = 0;
317 	} else {
318 		strcpy(str,"unknown");
319 	}
320 	if(bl_execute(bl, 0x0B, NULL, 0, id, 3)){
321 		d_printf("buslogic: cannot read config\n");
322 		return B_ERROR;
323 	}
324 	bl->scsi_id = id[2];
325 	d_printf("buslogic: Adapter SCSI ID = %d\n",bl->scsi_id);
326 
327     if(install_io_interrupt_handler(bl->irq, scsi_int_dispatch, bl, 0)
328        == B_ERROR) d_printf("buslogic: can't install irq handler\n");
329 
330         /* are we getting INTs? */
331     bl->done = 0;
332     spin(10000);
333     outb(BL_COMMAND_REG, 0x00);
334     spin(1000000);
335     if(bl->done) {
336         d_printf("buslogic: interrupt test passed\n");
337     } else {
338         d_printf("buslogic: interrupt test failed\n");
339         return B_ERROR;
340     }
341 
342         /* strict round-robin on */
343     id[0] = 0;
344     if(bl_execute(bl,0x8F, id, 1, NULL, 0)){
345         d_printf("buslogic: cannot enable strict round-robin mode\n");
346         return B_ERROR;
347     }
348 
349 
350     id[0] = bl->box_count;
351 { int mbaddr = toLE(bl->phys_mailboxes);
352     memcpy(id + 1, &(mbaddr),4);
353 }
354     if(bl_execute(bl, 0x81, id, 5, NULL, 0)){
355         d_printf("buslogic: cannot init mailboxes\n");
356         return B_ERROR;
357     }
358     d_printf("buslogic: %d mailboxes @ 0x%08xv/0x%08lxp\n",
359              bl->box_count, (uint) bl->out_boxes, bl->phys_mailboxes);
360 
361     return B_NO_ERROR;
362 }
363 
364 
365 
366 /* sim_invalid()
367 **
368 ** Generic invalid XPT command response
369 */
370 static long sim_invalid(BusLogic *bl, CCB_HEADER *ccbh)
371 {
372     ccbh->cam_status = CAM_REQ_INVALID;
373     d_printf("sim_invalid\n");
374     return B_ERROR;
375 }
376 
377 
378 /* Convert a CCB_SCSIIO into a BL_CCB32 and (possibly SG array).
379 **
380 **
381 */
382 
383 static long sim_execute_scsi_io(BusLogic *bl, CCB_HEADER *ccbh)
384 {
385     CCB_SCSIIO *ccb;
386     int cdb_len;
387     BL_CCB32 *bl_ccb;
388     BL_PRIV *priv;
389     uint32 priv_phys;
390     uint32 bl_ccb_phys;
391     physical_entry entries[2];
392     physical_entry *scratch;
393     uint32 tmp;
394     int i,t,req;
395 
396     ccb = (CCB_SCSIIO *) ccbh;
397 
398 #ifdef DEBUG_BUSLOGIC
399     req = atomic_add(&(bl->reqid),1);
400 #endif
401 
402         /* valid cdb len? */
403     cdb_len = ccb->cam_cdb_len;
404     if (cdb_len != 6 && cdb_len != 10 && cdb_len != 12) {
405         ccb->cam_ch.cam_status = CAM_REQ_INVALID;
406         return B_ERROR;
407     }
408 
409         /* acquire a CCB32 block */
410     acquire_sem(bl->ccb_count);
411 
412         /* protect the freelist and unchain the CCB32 from it */
413     acquire_sem(bl->ccb_lock);
414     bl_ccb = bl->first_ccb;
415     bl->first_ccb = bl_ccb->next;
416     release_sem(bl->ccb_lock);
417 
418     bl_ccb_phys = VirtToPhys(bl_ccb);
419 
420 
421         /* get contiguous area for bl_ccb in the private data area */
422     get_memory_map((void *)ccb->cam_sim_priv, 4096, entries, 2);
423 
424 	priv_phys = (uint32) entries[0].address;
425 	priv = (BL_PRIV *) ccb->cam_sim_priv;
426 
427         /* copy over the CDB */
428     if(ccb->cam_ch.cam_flags & CAM_CDB_POINTER) {
429         memcpy(bl_ccb->cdb, ccb->cam_cdb_io.cam_cdb_ptr, cdb_len);
430     } else {
431         memcpy(bl_ccb->cdb, ccb->cam_cdb_io.cam_cdb_bytes, cdb_len);
432     }
433 
434         /* fill out the ccb header */
435     bl_ccb->direction = BL_CCB_DIR_DEFAULT;
436     bl_ccb->length_cdb = cdb_len;
437     bl_ccb->length_sense = ccb->cam_sense_len;
438     bl_ccb->_reserved1 = bl_ccb->_reserved2 = 0;
439     bl_ccb->target_id = ccb->cam_ch.cam_target_id;
440     bl_ccb->lun_tag = ccb->cam_ch.cam_target_lun & 0x07;
441     bl_ccb->ccb_control = 0;
442     bl_ccb->link_id = 0;
443     bl_ccb->link = 0;
444     bl_ccb->sense = toLE(priv_phys);
445 
446         /* okay, this is really disgusting and could potentially
447            break if physical_entry{} changes format... we use the
448            sg list as a scratchpad.  Disgusting, but a start */
449 
450     scratch = (physical_entry *) priv->sg;
451 
452 
453 	if(ccb->cam_ch.cam_flags & CAM_SCATTER_VALID){
454 		/* we're using scatter gather -- things just got trickier */
455 		iovec *iov = (iovec *) ccb->cam_data_ptr;
456 		int j,sgcount = 0;
457 
458 		/* dprintf("buslogic: sg count = %d\n",ccb->cam_sglist_cnt);*/
459           /* multiple entries, use SG */
460 		bl_ccb->opcode = BL_CCB_OP_INITIATE_RETLEN_SG;
461 		bl_ccb->data = toLE(priv_phys + 256);
462 
463 		/* for each entry in the sglist we were given ... */
464 		for(t=0,i=0;i<ccb->cam_sglist_cnt;i++){
465 			/* map it ... */
466 		    get_memory_map(iov[i].iov_base, iov[i].iov_len, &(scratch[sgcount]),
467 	                   MAX_SCATTER - sgcount);
468 
469 			/* and make a bl sgentry for each chunk ... */
470 			for(j=sgcount;scratch[j].size && j<MAX_SCATTER;j++){
471 	            t += scratch[j].size;
472 				sgcount++;
473 	            dt_printf("buslogic/%d: SG %03d - 0x%08x (%d)\n",req,
474 			  j, (uint32) scratch[j].address, scratch[j].size);
475 
476 	            tmp = priv->sg[j].length;
477 	            priv->sg[j].length = toLE(priv->sg[j].phys);
478 	            priv->sg[j].phys = toLE(tmp);
479 	        }
480 
481 			if(scratch[j].size) panic("egads! sgseg overrun in BusLogic SIM");
482 		}
483         if(t != ccb->cam_dxfer_len){
484             dt_printf("buslogic/%d: error, %d != %d\n",req,t,ccb->cam_dxfer_len);
485             ccb->cam_ch.cam_status = CAM_REQ_INVALID;
486 
487                 /* put the CCB32 back on the freelist and release our lock */
488             acquire_sem(bl->ccb_lock);
489             bl_ccb->next = bl->first_ccb;
490             bl->first_ccb = bl_ccb;
491             release_sem(bl->ccb_lock);
492             release_sem(bl->ccb_count);
493             return B_ERROR;
494         }
495         /* total bytes in DataSegList */
496         bl_ccb->length_data = toLE(sgcount * 8);
497 	} else {
498 	    get_memory_map((void *)ccb->cam_data_ptr, ccb->cam_dxfer_len, scratch,
499 	                   MAX_SCATTER);
500 
501 	    if(scratch[1].size){
502 	            /* multiple entries, use SG */
503 	        bl_ccb->opcode = BL_CCB_OP_INITIATE_RETLEN_SG;
504 	        bl_ccb->data = toLE(priv_phys + 256);
505 	        for(t=0,i=0;scratch[i].size && i<MAX_SCATTER;i++){
506 	            t += scratch[i].size;
507 	            dt_printf("buslogic/%d: SG %03d - 0x%08x (%d)\n",req,
508 						  i, (uint32) scratch[i].address, scratch[i].size);
509 
510 	            tmp = priv->sg[i].length;
511 	            priv->sg[i].length = toLE(priv->sg[i].phys);
512 	            priv->sg[i].phys = toLE(tmp);
513 	        }
514 	        if(t != ccb->cam_dxfer_len){
515 	            dt_printf("buslogic/%d: error, %d != %d\n",req,t,ccb->cam_dxfer_len);
516 	            ccb->cam_ch.cam_status = CAM_REQ_INVALID;
517 
518 	                /* put the CCB32 back on the freelist and release our lock */
519 	            acquire_sem(bl->ccb_lock);
520 	            bl_ccb->next = bl->first_ccb;
521 	            bl->first_ccb = bl_ccb;
522 	            release_sem(bl->ccb_lock);
523 	            release_sem(bl->ccb_count);
524 	            return B_ERROR;
525 	        }
526 	            /* total bytes in DataSegList */
527 	        bl_ccb->length_data = toLE(i * 8);
528 
529 	    } else {
530 	        bl_ccb->opcode = BL_CCB_OP_INITIATE_RETLEN;
531 	            /* single entry, use direct */
532 	        t = bl_ccb->length_data = toLE(ccb->cam_dxfer_len);
533 	        bl_ccb->data = toLE((uint32) scratch[0].address);
534 	    }
535 	}
536 
537     dt_printf("buslogic/%d: targ %d, dxfr %d, scsi op = 0x%02x\n",req,
538 			  bl_ccb->target_id, t, bl_ccb->cdb[0]);
539 
540     acquire_sem(bl->hw_lock);
541 
542         /* check for box in use state XXX */
543     bl->out_boxes[bl->out_nextbox].ccb_phys = toLE(bl_ccb_phys);
544     bl->out_boxes[bl->out_nextbox].action_code = BL_ActionCode_Start;
545     bl->out_nextbox++;
546     if(bl->out_nextbox == bl->box_count) bl->out_nextbox = 0;
547     outb(BL_COMMAND_REG, 0x02);
548 
549 #ifndef SERIALIZE_REQS
550     release_sem(bl->hw_lock);
551 #endif
552 /*    d_printf("buslogic/%d: CCB %08x (%08xv) waiting on done\n",
553 	  req, bl_ccb_phys, (uint32) bl_ccb);*/
554     acquire_sem(bl_ccb->done);
555 /*    d_printf("buslogic/%d: CCB %08x (%08xv) done\n",
556 	  req, bl_ccb_phys, (uint32) bl_ccb);*/
557 
558 #ifdef SERIALIZE_REQS
559     release_sem(bl->hw_lock);
560 #endif
561 
562     if(bl_ccb->btstat){
563             /* XXX - error state xlat goes here */
564         switch(bl_ccb->btstat){
565 		case 0x11:
566 			ccb->cam_ch.cam_status = CAM_SEL_TIMEOUT;
567 			break;
568 		case 0x12:
569 			ccb->cam_ch.cam_status = CAM_DATA_RUN_ERR;
570 			break;
571 		case 0x13:
572 			ccb->cam_ch.cam_status = CAM_UNEXP_BUSFREE;
573 			break;
574 		case 0x22:
575 		case 0x23:
576 			ccb->cam_ch.cam_status = CAM_SCSI_BUS_RESET;
577 			break;
578 		case 0x34:
579 			ccb->cam_ch.cam_status = CAM_UNCOR_PARITY;
580 			break;
581 		default:
582 	        ccb->cam_ch.cam_status = CAM_REQ_INVALID;
583 		}
584         dt_printf("buslogic/%d: error stat %02x\n",req,bl_ccb->btstat);
585     } else {
586         dt_printf("buslogic/%d: data %d/%d, sense %d/%d\n", req,
587 				  bl_ccb->length_data, ccb->cam_dxfer_len,
588 				  bl_ccb->length_sense, ccb->cam_sense_len);
589 
590         ccb->cam_resid = bl_ccb->length_data;
591 
592             /* under what condition should we do this? */
593         memcpy(ccb->cam_sense_ptr, priv->sensedata, ccb->cam_sense_len);
594 
595         ccb->cam_scsi_status = bl_ccb->sdstat;
596 
597         if(bl_ccb->sdstat == 02){
598             ccb->cam_ch.cam_status = CAM_REQ_CMP_ERR | CAM_AUTOSNS_VALID;
599             ccb->cam_sense_resid = 0;
600             dt_printf("buslogic/%d: error scsi\n",req);
601         } else {
602             ccb->cam_ch.cam_status = CAM_REQ_CMP;
603             ccb->cam_sense_resid = bl_ccb->length_sense;
604             dt_printf("buslogic/%d: success scsi\n",req);
605                 /* put the CCB32 back on the freelist and release our lock */
606             acquire_sem(bl->ccb_lock);
607             bl_ccb->next = bl->first_ccb;
608             bl->first_ccb = bl_ccb;
609             release_sem(bl->ccb_lock);
610             release_sem(bl->ccb_count);
611             return 0;
612 
613         }
614     }
615 
616         /* put the CCB32 back on the freelist and release our lock */
617     acquire_sem(bl->ccb_lock);
618     bl_ccb->next = bl->first_ccb;
619     bl->first_ccb = bl_ccb;
620     release_sem(bl->ccb_lock);
621     release_sem(bl->ccb_count);
622     return B_ERROR;
623 }
624 
625 
626 /*
627 ** sim_path_inquiry returns info on the target/lun.
628 */
629 static long sim_path_inquiry(BusLogic *bl, CCB_HEADER *ccbh)
630 {
631     CCB_PATHINQ	*ccb;
632     d_printf("buslogic: sim_path_inquiry()\n");
633 
634     ccb = (CCB_PATHINQ *) ccbh;
635 
636     ccb->cam_version_num = SIM_VERSION;
637     ccb->cam_target_sprt = 0;
638     ccb->cam_hba_eng_cnt = 0;
639     memset (ccb->cam_vuhba_flags, 0, VUHBA);
640     ccb->cam_sim_priv = SIM_PRIV;
641     ccb->cam_async_flags = 0;
642     ccb->cam_initiator_id = bl->scsi_id;
643 	ccb->cam_hba_inquiry = bl->wide ? PI_WIDE_16 : 0;
644     strncpy (ccb->cam_sim_vid, sim_vendor_name, SIM_ID);
645     strncpy (ccb->cam_hba_vid, hba_vendor_name, HBA_ID);
646     ccb->cam_osd_usage = 0;
647     ccbh->cam_status = CAM_REQ_CMP;
648     return 0;
649 }
650 
651 
652 /*
653 ** sim_extended_path_inquiry returns info on the target/lun.
654 */
655 static long sim_extended_path_inquiry(BusLogic *bl, CCB_HEADER *ccbh)
656 {
657     CCB_EXTENDED_PATHINQ *ccb;
658 
659     sim_path_inquiry(bl, ccbh);
660     ccb = (CCB_EXTENDED_PATHINQ *) ccbh;
661     sprintf(ccb->cam_sim_version, "%d.0", SIM_VERSION);
662     sprintf(ccb->cam_hba_version, "%d.0", HBA_VERSION);
663     strncpy(ccb->cam_controller_family, controller_family, FAM_ID);
664     strncpy(ccb->cam_controller_type, bl->productname, TYPE_ID);
665     return 0;
666 }
667 
668 
669 /*
670 ** sim_release_queue unfreezes the target/lun's request queue.
671 */
672 static long sim_sim_release_queue(BusLogic *bl, CCB_HEADER *ccbh)
673 {
674     ccbh->cam_status = CAM_REQ_INVALID;
675     return B_ERROR;
676 }
677 
678 
679 /*
680 ** sim_set_async_callback registers a callback routine for the
681 ** target/lun;
682 */
683 static long sim_set_async_callback(BusLogic *bl, CCB_HEADER *ccbh)
684 {
685     ccbh->cam_status = CAM_REQ_INVALID;
686     return B_ERROR;
687 }
688 
689 
690 /*
691 ** sim_abort aborts a pending or queued scsi operation.
692 */
693 static long sim_abort(BusLogic *bl, CCB_HEADER *ccbh)
694 {
695     ccbh->cam_status = CAM_REQ_INVALID;
696     return B_ERROR;
697 }
698 
699 
700 /*
701 ** sim_reset_bus resets the scsi bus.
702 */
703 static long sim_reset_bus(BusLogic *bl, CCB_HEADER *ccbh)
704 {
705     ccbh->cam_status = CAM_REQ_CMP;
706     return 0;
707 }
708 
709 
710 /*
711 ** sim_reset_device resets the target/lun with the scsi "bus
712 ** device reset" command.
713 */
714 static long sim_reset_device(BusLogic *bl, CCB_HEADER *ccbh)
715 {
716     ccbh->cam_status = CAM_REQ_INVALID;
717     return B_ERROR;
718 }
719 
720 
721 /*
722 ** sim_terminate_process terminates the scsi i/o request without
723 ** corrupting the medium.  It is used to stop lengthy requests
724 ** when a higher priority request is available.
725 **
726 ** Not yet implemented.
727 */
728 static long sim_terminate_process(BusLogic *bl, CCB_HEADER *ccbh)
729 {
730     ccbh->cam_status = CAM_REQ_INVALID;
731     return B_ERROR;
732 }
733 
734 
735 /*
736 ** scsi_sim_action performes the scsi i/o command embedded in the
737 ** passed ccb.
738 **
739 ** The target/lun ids are assumed to be in range.
740 */
741 static long sim_action(BusLogic *bl, CCB_HEADER *ccbh)
742 {
743     static long (*sim_functions[])(BusLogic *, CCB_HEADER *) = {
744         sim_invalid,		/* do nothing */
745         sim_execute_scsi_io,	/* execute a scsi i/o command */
746         sim_invalid,		/* get device type info */
747         sim_path_inquiry,	/* path inquiry */
748         sim_sim_release_queue,	/* release a frozen SIM queue */
749         sim_set_async_callback,	/* set async callback parameters */
750         sim_invalid,		/* set device type info */
751         sim_invalid,		/* invalid function code */
752         sim_invalid,		/* invalid function code */
753         sim_invalid,		/* invalid function code */
754         sim_invalid,		/* invalid function code */
755         sim_invalid,		/* invalid function code */
756         sim_invalid,		/* invalid function code */
757         sim_invalid,		/* invalid function code */
758         sim_invalid,		/* invalid function code */
759         sim_invalid,		/* invalid function code */
760         sim_abort,		/* abort the selected CCB */
761         sim_reset_bus,		/* reset a SCSI bus */
762         sim_reset_device,	/* reset a SCSI device */
763         sim_terminate_process	/* terminate an i/o process */
764     };
765     uchar op;
766 
767     /* d_printf("buslogic: sim_execute(), op = %d\n", ccbh->cam_func_code); */
768 
769 		/* check for function codes out of range of dispatch table */
770     op = ccbh->cam_func_code;
771     if ((op >= sizeof (sim_functions) / sizeof (long (*)())) &&
772         (op != XPT_EXTENDED_PATH_INQ)) {
773             /* check for our vendor-uniques (if any) here... */
774         ccbh->cam_status = CAM_REQ_INVALID;
775         return -1;
776     }
777 
778     ccbh->cam_status = CAM_REQ_INPROG;
779     if (op == XPT_EXTENDED_PATH_INQ) {
780         return sim_extended_path_inquiry(bl, ccbh);
781     } else {
782         return (*sim_functions [op])(bl, ccbh);
783     }
784 }
785 
786 
787 static char *hextab = "0123456789ABCDEF";
788 
789 /*
790 ** Allocate the actual memory for the cardinfo object
791 */
792 static BusLogic *create_cardinfo(int num, int iobase, int irq)
793 {
794     uchar *a;
795     area_id aid;
796     int i;
797     physical_entry entries[5];
798     char name[9] = { 'b', 'l', '_', 'c', 'c', 'b', '0', '0', 0 };
799 
800     BusLogic *bl = (BusLogic *) malloc(sizeof(BusLogic));
801 
802 #ifndef __i386__
803 	i = map_physical_memory("bl_regs", iobase,  4096,
804 		B_ANY_KERNEL_ADDRESS, B_READ_AREA | B_WRITE_AREA, &a);
805 	iobase = (uint32) a;
806 	if(i < 0) {
807 		dprintf("buslogic: can't map registers...\n");
808 	}
809 #endif
810 
811     bl->id = num;
812     bl->iobase = iobase;
813     bl->irq = irq;
814     bl->out_nextbox = bl->in_nextbox = 0;
815 
816         /* create our 20k workspace.  First 4k goes to 510 mailboxes.
817         ** remaining 16k is used for up to 256 CCB32's
818         */
819     a = NULL;
820 
821 #if BOOT
822         /* life in the bootstrap is a bit different... */
823         /* can't be sure of getting contig pages -- scale
824            stuff down so we can live in just one page */
825     bl->box_count = 4;
826     if(!(a = malloc(4096*2))) {
827         free(bl);
828         return NULL;
829     }
830     a = (uchar *) ((((uint32) a) & 0xFFFFF000) + 0x1000);
831     get_memory_map(a, 4096, entries, 2);
832 #else
833     bl->box_count = MAX_CCB_COUNT;
834     aid = create_area("bl_workspace", (void **)&a, B_ANY_KERNEL_ADDRESS, 4096*5,
835 		B_32_BIT_CONTIGUOUS, B_READ_AREA | B_WRITE_AREA);
836     if(aid == B_ERROR || aid == B_BAD_VALUE || aid == B_NO_MEMORY) {
837         free(bl);
838         return NULL;
839     }
840     get_memory_map(a, 4096*5, entries, 2);
841 #endif
842 
843         /* figure virtual <-> physical translations */
844     bl->phys_to_virt = ((uint) a) - ((uint) entries[0].address);
845     bl->virt_to_phys = (((uint) entries[0].address - (uint) a));
846     bl->phys_mailboxes = (uint) entries[0].address;
847 
848         /* initialize all mailboxes to empty */
849     bl->out_boxes = (BL_Out_Mailbox32 *) a;
850     bl->in_boxes = (BL_In_Mailbox32 *) (a + (8 * bl->box_count));
851     for(i=0;i<bl->box_count;i++){
852         bl->out_boxes[i].action_code = BL_ActionCode_NotInUse;
853         bl->in_boxes[i].completion_code = BL_CompletionCode_NotInUse;
854     }
855 
856         /* setup the CCB32 cache */
857 #if BOOT
858     bl->ccb = (BL_CCB32 *) (((uchar *)a) + 1024);
859 #else
860     bl->ccb = (BL_CCB32 *) (((uchar *)a) + 4096);
861 #endif
862     bl->first_ccb = NULL;
863     for(i=0;i<bl->box_count;i++){
864         name[6] = hextab[(i & 0xF0) >> 4];
865         name[7] = hextab[i & 0x0F];
866         bl->ccb[i].done = create_sem(0, name);
867         bl->ccb[i].next = bl->first_ccb;
868         bl->first_ccb = &(bl->ccb[i]);
869     }
870 
871     bl->hw_lock = create_sem(1, "bl_hw_lock");
872     bl->ccb_lock = create_sem(1, "bl_ccb_lock");
873     bl->ccb_count = create_sem(MAX_CCB_COUNT, "bl_ccb_count");
874     bl->reqid = 0;
875 
876     return bl;
877 }
878 
879 
880 /*
881 ** Multiple Card Cruft
882 */
883 #define MAXCARDS 4
884 
885 static BusLogic *cardinfo[MAXCARDS] = { NULL, NULL, NULL, NULL };
886 
887 static long sim_init0(void)                { return init_buslogic(cardinfo[0]); }
888 static long sim_init1(void)                { return init_buslogic(cardinfo[1]); }
889 static long sim_init2(void)                { return init_buslogic(cardinfo[2]); }
890 static long sim_init3(void)                { return init_buslogic(cardinfo[3]); }
891 static long sim_action0(CCB_HEADER *ccbh)  { return sim_action(cardinfo[0],ccbh); }
892 static long sim_action1(CCB_HEADER *ccbh)  { return sim_action(cardinfo[1],ccbh); }
893 static long sim_action2(CCB_HEADER *ccbh)  { return sim_action(cardinfo[2],ccbh); }
894 static long sim_action3(CCB_HEADER *ccbh)  { return sim_action(cardinfo[3],ccbh); }
895 
896 
897 static long (*sim_init_funcs[MAXCARDS])(void) = {
898     sim_init0, sim_init1, sim_init2, sim_init3
899 };
900 
901 static long (*sim_action_funcs[MAXCARDS])(CCB_HEADER *) = {
902     sim_action0, sim_action1, sim_action2, sim_action3
903 };
904 
905 
906 /*
907 ** Detect the controller and register the SIM with the CAM layer.
908 ** returns the number of controllers installed...
909 */
910 static int
911 sim_install_buslogic(void)
912 {
913     int i, iobase, irq;
914     int cardcount = 0;
915     pci_info h;
916     CAM_SIM_ENTRY entry;
917 
918    /* d_printf("buslogic: sim_install()\n"); */
919 
920     for (i = 0; ; i++) {
921         if ((*pci->get_nth_pci_info) (i, &h) != B_NO_ERROR) {
922             /* if(!cardcount) d_printf("buslogic: no controller found\n"); */
923             break;
924         }
925 
926         if ((h.vendor_id == PCI_VENDOR_BUSLOGIC) &&
927             (h.device_id == PCI_DEVICE_MULTIMASTER)) {
928 
929 #ifdef __i386__
930             iobase = h.u.h0.base_registers[0];
931 #else
932             iobase = h.u.h0.base_registers[1];
933 #endif
934             irq = h.u.h0.interrupt_line;
935 
936             d_printf("buslogic%d: controller @ 0x%08x, irq %d\n",
937                      cardcount, iobase, irq);
938     		if((irq == 0) || (irq > 128)) {
939 				dprintf("buslogic%d: bad irq %d\n",cardcount,irq);
940         		continue;
941     		}
942 
943             if(cardcount == MAXCARDS){
944                 d_printf("buslogic: too many controllers!\n");
945                 return cardcount;
946             }
947 
948             if((cardinfo[cardcount] = create_cardinfo(cardcount,iobase,irq))){
949                 entry.sim_init = sim_init_funcs[cardcount];
950                 entry.sim_action = sim_action_funcs[cardcount];
951                 (*cam->xpt_bus_register)(&entry);
952                 cardcount++;
953             } else {
954                 d_printf("buslogic: cannot allocate cardinfo\n");
955             }
956         }
957     }
958 
959     return cardcount;
960 }
961 
962 static status_t std_ops(int32 op, ...)
963 {
964 	switch(op) {
965 	case B_MODULE_INIT:
966 		if (get_module(pci_name, (module_info **) &pci) != B_OK)
967 			return B_ERROR;
968 
969 		if (get_module(cam_name, (module_info **) &cam) != B_OK) {
970 			put_module(pci_name);
971 			return B_ERROR;
972 		}
973 
974 		if(sim_install_buslogic()){
975 			return B_OK;
976 		}
977 
978 		put_module(pci_name);
979 		put_module(cam_name);
980 		return B_ERROR;
981 
982 	case B_MODULE_UNINIT:
983 		put_module(pci_name);
984 		put_module(cam_name);
985 		return B_OK;
986 
987 	default:
988 		return B_ERROR;
989 	}
990 }
991 
992 #if BUILD_LOADABLE
993 static
994 #endif
995 sim_module_info sim_buslogic_module = {
996 	{ "busses/scsi/buslogic/v1", 0, &std_ops }
997 };
998 
999 #if BUILD_LOADABLE
1000 _EXPORT module_info  *modules[] =
1001 {
1002 	(module_info *) &sim_buslogic_module,
1003 	NULL
1004 };
1005 #endif
1006