cmd->acc_io.aio_data = kvtop((caddr_t)&inq);
cmd->acc_io.aio_data = htole32(pa);
ami_attach(sc)	struct ami_softc *sc;{	/* struct ami_rawsoftc *rsc; */	struct ami_ccb	*ccb;	struct ami_iocmd *cmd;	struct ami_sgent *sg;	bus_dmamap_t idatamap;	bus_dma_segment_t idataseg[1];	const char *p;	void	*idata;	int	error;	if (!(idata = ami_allocmem(sc->dmat, &idatamap, idataseg,	    NBPG, 1, "init data"))) {		ami_freemem(sc->dmat, &idatamap, idataseg,		    NBPG, 1, "init data");		return 1;	}	sc->sc_cmds = ami_allocmem(sc->dmat, &sc->sc_cmdmap, sc->sc_cmdseg,	    sizeof(struct ami_iocmd), AMI_MAXCMDS+1, "command");	if (!sc->sc_cmds) {		ami_dispose(sc);		ami_freemem(sc->dmat, &idatamap,		    idataseg, NBPG, 1, "init data");		return 1;	}	sc->sc_sgents = ami_allocmem(sc->dmat, &sc->sc_sgmap, sc->sc_sgseg,	    sizeof(struct ami_sgent) * AMI_SGEPERCMD, AMI_MAXCMDS+1, "sglist");	if (!sc->sc_sgents) {		ami_dispose(sc);		ami_freemem(sc->dmat, &idatamap,		    idataseg, NBPG, 1, "init data");		return 1;	}	TAILQ_INIT(&sc->sc_ccbq);	TAILQ_INIT(&sc->sc_ccb2q);	TAILQ_INIT(&sc->sc_ccbdone);	TAILQ_INIT(&sc->sc_free_ccb);	/* 0th command is a mailbox */	for (ccb = &sc->sc_ccbs[AMI_MAXCMDS-1],	     cmd = sc->sc_cmds  + sizeof(*cmd) * AMI_MAXCMDS,	     sg = sc->sc_sgents + sizeof(*sg)  * AMI_MAXCMDS * AMI_SGEPERCMD;	     cmd >= (struct ami_iocmd *)sc->sc_cmds;	     cmd--, ccb--, sg -= AMI_SGEPERCMD) {		cmd->acc_id = cmd - (struct ami_iocmd *)sc->sc_cmds;		if (cmd->acc_id) {			error = bus_dmamap_create(sc->dmat,			    AMI_MAXFER, AMI_MAXOFFSETS, AMI_MAXFER, 0,			    BUS_DMA_NOWAIT | BUS_DMA_ALLOCNOW,			    &ccb->ccb_dmamap);			if (error) {				printf(": cannot create ccb dmamap (%d)\n",				    error);				ami_dispose(sc);				ami_freemem(sc->dmat, &idatamap,				    idataseg, NBPG, 1, "init data");				return (1);			}			ccb->ccb_sc = sc;			ccb->ccb_cmd = cmd;			ccb->ccb_state = AMI_CCB_FREE;			ccb->ccb_cmdpa = sc->sc_cmdseg[0].ds_addr +			    cmd->acc_id * sizeof(*cmd);			ccb->ccb_sglist = sg;			ccb->ccb_sglistpa = sc->sc_sgseg[0].ds_addr +			    cmd->acc_id * sizeof(*sg) * AMI_SGEPERCMD;			TAILQ_INSERT_TAIL(&sc->sc_free_ccb, ccb, ccb_link);		} else {			sc->sc_mbox = cmd;			sc->sc_mbox_pa = sc->sc_cmdseg[0].ds_addr;		}	}	timeout_set(&sc->sc_poll_tmo, (void (*)__P((void *)))ami_intr, sc);	(sc->sc_init)(sc);	{		paddr_t	pa = idataseg[0].ds_addr;		ami_lock_t lock;		lock = AMI_LOCK_AMI(sc);		ccb = ami_get_ccb(sc);		cmd = ccb->ccb_cmd;		/* try FC inquiry first */		cmd->acc_cmd = AMI_FCOP;		cmd->acc_io.aio_channel = AMI_FC_EINQ3;		cmd->acc_io.aio_param = AMI_FC_EINQ3_SOLICITED_FULL;		cmd->acc_io.aio_data = pa;		if (ami_cmd(ccb, 0, 1) == 0) {			struct ami_fc_einquiry *einq = idata;			struct ami_fc_prodinfo *pi = idata;			sc->sc_nunits = einq->ain_nlogdrv;			ami_copyhds(sc, einq->ain_ldsize, einq->ain_ldprop,			    einq->ain_ldstat);			ccb = ami_get_ccb(sc);			cmd = ccb->ccb_cmd;			cmd->acc_cmd = AMI_FCOP;			cmd->acc_io.aio_channel = AMI_FC_PRODINF;			cmd->acc_io.aio_param = 0;			cmd->acc_io.aio_data = pa;			if (ami_cmd(ccb, 0, 1) == 0) {				sc->sc_maxunits = AMI_BIG_MAX_LDRIVES;				bcopy (pi->api_fwver, sc->sc_fwver, 16);				sc->sc_fwver[16] = '\0';				bcopy (pi->api_biosver, sc->sc_biosver, 16);				sc->sc_biosver[16] = '\0';				sc->sc_channels = pi->api_channels;				sc->sc_targets = pi->api_fcloops;				sc->sc_memory = pi->api_ramsize;				sc->sc_maxcmds = pi->api_maxcmd;				p = "FC loop";			}		}		if (sc->sc_maxunits == 0) {			struct ami_inquiry *inq = idata;			ccb = ami_get_ccb(sc);			cmd = ccb->ccb_cmd;			cmd->acc_cmd = AMI_EINQUIRY;			cmd->acc_io.aio_channel = 0;			cmd->acc_io.aio_param = 0;			cmd->acc_io.aio_data = pa;			if (ami_cmd(ccb, 0, 1) != 0) {				ccb = ami_get_ccb(sc);				cmd = ccb->ccb_cmd;				cmd->acc_cmd = AMI_INQUIRY;				cmd->acc_io.aio_channel = 0;				cmd->acc_io.aio_param = 0;				cmd->acc_io.aio_data = kvtop((caddr_t)&inq);				if (ami_cmd(ccb, 0, 1) != 0) {					AMI_UNLOCK_AMI(sc, lock);					printf(": cannot do inquiry\n");					ami_dispose(sc);					ami_freemem(sc->dmat, &idatamap,					    idataseg, NBPG, 1, "init data");					return (1);				}			}			sc->sc_maxunits = AMI_MAX_LDRIVES;			sc->sc_nunits = inq->ain_nlogdrv;			ami_copyhds(sc, inq->ain_ldsize, inq->ain_ldprop,			    inq->ain_ldstat);			bcopy (inq->ain_fwver, sc->sc_fwver, 4);			sc->sc_fwver[4] = '\0';			bcopy (inq->ain_biosver, sc->sc_biosver, 4);			sc->sc_biosver[4] = '\0';			sc->sc_channels = inq->ain_channels;			sc->sc_targets = inq->ain_targets;			sc->sc_memory = inq->ain_ramsize;			sc->sc_maxcmds = inq->ain_maxcmd;			p = "target";		}		AMI_UNLOCK_AMI(sc, lock);		if (sc->sc_maxcmds > AMI_MAXCMDS)			sc->sc_maxcmds = 1 /* AMI_MAXCMDS */;	}	ami_freemem(sc->dmat, &idatamap, idataseg, NBPG, 1, "init data");	/* hack for hp netraid version encoding */	if ('A' <= sc->sc_fwver[2] && sc->sc_fwver[2] <= 'Z' &&	    sc->sc_fwver[1] < ' ' && sc->sc_fwver[0] < ' ' &&	    'A' <= sc->sc_biosver[2] && sc->sc_biosver[2] <= 'Z' &&	    sc->sc_biosver[1] < ' ' && sc->sc_biosver[0] < ' ') {		sprintf(sc->sc_fwver, "%c.%02d.%02d", sc->sc_fwver[2],		    sc->sc_fwver[1], sc->sc_fwver[0]);		sprintf(sc->sc_biosver, "%c.%02d.%02d", sc->sc_biosver[2],		    sc->sc_biosver[1], sc->sc_biosver[0]);	}	printf(": FW %s, BIOS v%s, %dMB RAM\n"	     "%s: %d channels, %d %ss, %d logical drives\n",	    sc->sc_fwver, sc->sc_biosver, sc->sc_memory,	    sc->sc_dev.dv_xname,	    sc->sc_channels, sc->sc_targets, p, sc->sc_nunits);	/* TODO: fetch & print cache strategy */	/* TODO: fetch & print scsi and raid info */	sc->sc_link.device = &ami_dev;	sc->sc_link.openings = sc->sc_maxcmds;	sc->sc_link.adapter_softc = sc;	sc->sc_link.adapter = &ami_switch;	sc->sc_link.adapter_target = sc->sc_maxunits;	sc->sc_link.adapter_buswidth = sc->sc_maxunits;	config_found(&sc->sc_dev, &sc->sc_link, scsiprint);#if 0	rsc = malloc(sizeof(struct ami_rawsoftc) * sc->sc_channels,	    M_DEVBUF, M_NOWAIT);	if (!rsc) {		printf("%s: no memory for raw interface\n",		    sc->sc_dev.dv_xname);		return (0);	}	bzero(rsc, sizeof(struct ami_rawsoftc) * sc->sc_channels);	for (sc->sc_rawsoftcs = rsc;	     rsc < &sc->sc_rawsoftcs[sc->sc_channels]; rsc++) {		/* TODO fetch and print channel properties */		rsc->sc_softc = sc;		rsc->sc_channel = rsc - sc->sc_rawsoftcs;		rsc->sc_link.device = &ami_raw_dev;		rsc->sc_link.openings = sc->sc_maxcmds;		rsc->sc_link.adapter_softc = rsc;		rsc->sc_link.adapter = &ami_raw_switch;		/* TODO fetch it from the controller */		rsc->sc_link.adapter_target = sc->sc_targets;		rsc->sc_link.adapter_buswidth = sc->sc_targets;		config_found(&sc->sc_dev, &rsc->sc_link, scsiprint);	}#endif	return 0;}