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
74static char sim_vendor_name[]   = "Be, Inc.";
75static char hba_vendor_name[]   = "BusLogic";
76static char controller_family[] = "MultiMaster PCI";
77
78static pci_module_info		*pci;
79static cam_for_sim_module_info	*cam;
80
81static char	cam_name[] = B_CAM_FOR_SIM_MODULE_NAME;
82static 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
101static int32
102scsi_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*/
152static 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*/
244static 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*/
370static 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
383static 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*/
629static 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*/
655static 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*/
672static 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*/
683static 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*/
693static 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*/
703static 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*/
714static 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*/
728static 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*/
741static 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
787static char *hextab = "0123456789ABCDEF";
788
789/*
790** Allocate the actual memory for the cardinfo object
791*/
792static 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
885static BusLogic *cardinfo[MAXCARDS] = { NULL, NULL, NULL, NULL };
886
887static long sim_init0(void)                { return init_buslogic(cardinfo[0]); }
888static long sim_init1(void)                { return init_buslogic(cardinfo[1]); }
889static long sim_init2(void)                { return init_buslogic(cardinfo[2]); }
890static long sim_init3(void)                { return init_buslogic(cardinfo[3]); }
891static long sim_action0(CCB_HEADER *ccbh)  { return sim_action(cardinfo[0],ccbh); }
892static long sim_action1(CCB_HEADER *ccbh)  { return sim_action(cardinfo[1],ccbh); }
893static long sim_action2(CCB_HEADER *ccbh)  { return sim_action(cardinfo[2],ccbh); }
894static long sim_action3(CCB_HEADER *ccbh)  { return sim_action(cardinfo[3],ccbh); }
895
896
897static long (*sim_init_funcs[MAXCARDS])(void) = {
898    sim_init0, sim_init1, sim_init2, sim_init3
899};
900
901static 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*/
910static int
911sim_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
962static 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
993static
994#endif
995sim_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