17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5a888983fSap  * Common Development and Distribution License (the "License").
6a888983fSap  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
228c067cfdSAlan Perry  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
26*3fe80ca4SDan Cross /*
27*3fe80ca4SDan Cross  * Copyright 2023 Oxide Computer Company
28*3fe80ca4SDan Cross  */
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate  * 1394 mass storage HBA driver
327c478bd9Sstevel@tonic-gate  */
337c478bd9Sstevel@tonic-gate 
347c478bd9Sstevel@tonic-gate #include <sys/param.h>
357c478bd9Sstevel@tonic-gate #include <sys/errno.h>
367c478bd9Sstevel@tonic-gate #include <sys/cred.h>
377c478bd9Sstevel@tonic-gate #include <sys/conf.h>
387c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
397c478bd9Sstevel@tonic-gate #include <sys/stat.h>
407c478bd9Sstevel@tonic-gate #include <sys/byteorder.h>
417c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
427c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate #include <sys/1394/targets/scsa1394/impl.h>
457c478bd9Sstevel@tonic-gate #include <sys/1394/targets/scsa1394/cmd.h>
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate /* DDI/DKI entry points */
487c478bd9Sstevel@tonic-gate static int	scsa1394_attach(dev_info_t *, ddi_attach_cmd_t);
497c478bd9Sstevel@tonic-gate static int	scsa1394_detach(dev_info_t *, ddi_detach_cmd_t);
507c478bd9Sstevel@tonic-gate static int	scsa1394_power(dev_info_t *, int, int);
51f5488aa8Sbharding static int	scsa1394_cpr_suspend(dev_info_t *);
52f5488aa8Sbharding static void	scsa1394_cpr_resume(dev_info_t *);
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate /* configuration routines */
557c478bd9Sstevel@tonic-gate static void	scsa1394_cleanup(scsa1394_state_t *, int);
567c478bd9Sstevel@tonic-gate static int	scsa1394_attach_1394(scsa1394_state_t *);
577c478bd9Sstevel@tonic-gate static void	scsa1394_detach_1394(scsa1394_state_t *);
587c478bd9Sstevel@tonic-gate static int	scsa1394_attach_threads(scsa1394_state_t *);
597c478bd9Sstevel@tonic-gate static void	scsa1394_detach_threads(scsa1394_state_t *);
607c478bd9Sstevel@tonic-gate static int	scsa1394_attach_scsa(scsa1394_state_t *);
617c478bd9Sstevel@tonic-gate static void	scsa1394_detach_scsa(scsa1394_state_t *);
627c478bd9Sstevel@tonic-gate static int	scsa1394_create_cmd_cache(scsa1394_state_t *);
637c478bd9Sstevel@tonic-gate static void	scsa1394_destroy_cmd_cache(scsa1394_state_t *);
647c478bd9Sstevel@tonic-gate static int	scsa1394_add_events(scsa1394_state_t *);
657c478bd9Sstevel@tonic-gate static void	scsa1394_remove_events(scsa1394_state_t *);
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate /* device configuration */
687c478bd9Sstevel@tonic-gate static int	scsa1394_scsi_bus_config(dev_info_t *, uint_t,
697c478bd9Sstevel@tonic-gate 		ddi_bus_config_op_t, void *, dev_info_t **);
707c478bd9Sstevel@tonic-gate static int	scsa1394_scsi_bus_unconfig(dev_info_t *, uint_t,
717c478bd9Sstevel@tonic-gate 		ddi_bus_config_op_t, void *);
727c478bd9Sstevel@tonic-gate static void	scsa1394_create_children(scsa1394_state_t *);
737c478bd9Sstevel@tonic-gate static void	scsa1394_bus_reset(dev_info_t *, ddi_eventcookie_t, void *,
747c478bd9Sstevel@tonic-gate 		void *);
757c478bd9Sstevel@tonic-gate static void	scsa1394_disconnect(dev_info_t *, ddi_eventcookie_t, void *,
767c478bd9Sstevel@tonic-gate 		void *);
777c478bd9Sstevel@tonic-gate static void	scsa1394_reconnect(dev_info_t *, ddi_eventcookie_t, void *,
787c478bd9Sstevel@tonic-gate 		void *);
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate /* SCSA HBA entry points */
817c478bd9Sstevel@tonic-gate static int	scsa1394_scsi_tgt_init(dev_info_t *, dev_info_t *,
827c478bd9Sstevel@tonic-gate 		scsi_hba_tran_t *, struct scsi_device *);
837c478bd9Sstevel@tonic-gate static void	scsa1394_scsi_tgt_free(dev_info_t *, dev_info_t *,
847c478bd9Sstevel@tonic-gate 		scsi_hba_tran_t *, struct scsi_device *);
857c478bd9Sstevel@tonic-gate static int	scsa1394_scsi_tgt_probe(struct scsi_device *, int (*)());
867c478bd9Sstevel@tonic-gate static int	scsa1394_probe_g0_nodata(struct scsi_device *, int (*)(),
877c478bd9Sstevel@tonic-gate 		uchar_t, uint_t, uint_t);
887c478bd9Sstevel@tonic-gate static int	scsa1394_probe_tran(struct scsi_pkt *);
897c478bd9Sstevel@tonic-gate static struct scsi_pkt *scsa1394_scsi_init_pkt(struct scsi_address *,
907c478bd9Sstevel@tonic-gate 		struct scsi_pkt *, struct buf *, int, int, int, int,
917c478bd9Sstevel@tonic-gate 		int (*)(), caddr_t arg);
927c478bd9Sstevel@tonic-gate static void	scsa1394_scsi_destroy_pkt(struct scsi_address *,
937c478bd9Sstevel@tonic-gate 		struct scsi_pkt *);
947c478bd9Sstevel@tonic-gate static int	scsa1394_scsi_start(struct scsi_address *, struct scsi_pkt *);
957c478bd9Sstevel@tonic-gate static int	scsa1394_scsi_abort(struct scsi_address *, struct scsi_pkt *);
967c478bd9Sstevel@tonic-gate static int	scsa1394_scsi_reset(struct scsi_address *, int);
977c478bd9Sstevel@tonic-gate static int	scsa1394_scsi_getcap(struct scsi_address *, char *, int);
987c478bd9Sstevel@tonic-gate static int	scsa1394_scsi_setcap(struct scsi_address *, char *, int, int);
997c478bd9Sstevel@tonic-gate static void	scsa1394_scsi_dmafree(struct scsi_address *, struct scsi_pkt *);
1007c478bd9Sstevel@tonic-gate static void	scsa1394_scsi_sync_pkt(struct scsi_address *,
1017c478bd9Sstevel@tonic-gate 		struct scsi_pkt *);
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate /* pkt resource allocation routines */
1047c478bd9Sstevel@tonic-gate static int	scsa1394_cmd_cache_constructor(void *, void *, int);
1057c478bd9Sstevel@tonic-gate static void	scsa1394_cmd_cache_destructor(void *, void *);
1067c478bd9Sstevel@tonic-gate static int	scsa1394_cmd_ext_alloc(scsa1394_state_t *, scsa1394_cmd_t *,
1077c478bd9Sstevel@tonic-gate 		int);
1087c478bd9Sstevel@tonic-gate static void	scsa1394_cmd_ext_free(scsa1394_state_t *, scsa1394_cmd_t *);
1097c478bd9Sstevel@tonic-gate static int	scsa1394_cmd_cdb_dma_alloc(scsa1394_state_t *, scsa1394_cmd_t *,
1107c478bd9Sstevel@tonic-gate 		int, int (*)(), caddr_t);
1117c478bd9Sstevel@tonic-gate static void	scsa1394_cmd_cdb_dma_free(scsa1394_state_t *, scsa1394_cmd_t *);
1127c478bd9Sstevel@tonic-gate static int	scsa1394_cmd_buf_dma_alloc(scsa1394_state_t *, scsa1394_cmd_t *,
1137c478bd9Sstevel@tonic-gate 		int, int (*)(), caddr_t, struct buf *);
1147c478bd9Sstevel@tonic-gate static void	scsa1394_cmd_buf_dma_free(scsa1394_state_t *, scsa1394_cmd_t *);
1157c478bd9Sstevel@tonic-gate static int	scsa1394_cmd_dmac2seg(scsa1394_state_t *, scsa1394_cmd_t *,
1167c478bd9Sstevel@tonic-gate 		ddi_dma_cookie_t *, uint_t, int);
1177c478bd9Sstevel@tonic-gate static void	scsa1394_cmd_seg_free(scsa1394_state_t *, scsa1394_cmd_t *);
1187c478bd9Sstevel@tonic-gate static int	scsa1394_cmd_pt_dma_alloc(scsa1394_state_t *, scsa1394_cmd_t *,
1197c478bd9Sstevel@tonic-gate 		int (*)(), caddr_t, int);
1207c478bd9Sstevel@tonic-gate static void	scsa1394_cmd_pt_dma_free(scsa1394_state_t *, scsa1394_cmd_t *);
1217c478bd9Sstevel@tonic-gate static int	scsa1394_cmd_buf_addr_alloc(scsa1394_state_t *,
1227c478bd9Sstevel@tonic-gate 		scsa1394_cmd_t *);
1237c478bd9Sstevel@tonic-gate static void	scsa1394_cmd_buf_addr_free(scsa1394_state_t *,
1247c478bd9Sstevel@tonic-gate 		scsa1394_cmd_t *);
1257c478bd9Sstevel@tonic-gate static int	scsa1394_cmd_buf_dma_move(scsa1394_state_t *, scsa1394_cmd_t *);
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate /* pkt and data transfer routines */
1297c478bd9Sstevel@tonic-gate static void	scsa1394_prepare_pkt(scsa1394_state_t *, struct scsi_pkt *);
1307c478bd9Sstevel@tonic-gate static void	scsa1394_cmd_fill_cdb(scsa1394_lun_t *, scsa1394_cmd_t *);
1317c478bd9Sstevel@tonic-gate static void	scsa1394_cmd_fill_cdb_rbc(scsa1394_lun_t *, scsa1394_cmd_t *);
1327c478bd9Sstevel@tonic-gate static void	scsa1394_cmd_fill_cdb_other(scsa1394_lun_t *, scsa1394_cmd_t *);
1337c478bd9Sstevel@tonic-gate static void	scsa1394_cmd_fill_cdb_len(scsa1394_cmd_t *, int);
1347c478bd9Sstevel@tonic-gate static void	scsa1394_cmd_fill_cdb_lba(scsa1394_cmd_t *, int);
1357c478bd9Sstevel@tonic-gate static void	scsa1394_cmd_fill_12byte_cdb_len(scsa1394_cmd_t *, int);
1367c478bd9Sstevel@tonic-gate static void	scsa1394_cmd_fill_read_cd_cdb_len(scsa1394_cmd_t *, int);
1377c478bd9Sstevel@tonic-gate static int	scsa1394_cmd_read_cd_blk_size(uchar_t);
1387c478bd9Sstevel@tonic-gate static int	scsa1394_cmd_fake_mode_sense(scsa1394_state_t *,
1397c478bd9Sstevel@tonic-gate 		scsa1394_cmd_t *);
1407c478bd9Sstevel@tonic-gate static int	scsa1394_cmd_fake_inquiry(scsa1394_state_t *, scsa1394_cmd_t *);
1417c478bd9Sstevel@tonic-gate static int	scsa1394_cmd_fake_comp(scsa1394_state_t *, scsa1394_cmd_t *);
1427c478bd9Sstevel@tonic-gate static int	scsa1394_cmd_setup_next_xfer(scsa1394_lun_t *,
1437c478bd9Sstevel@tonic-gate 		scsa1394_cmd_t *);
1447c478bd9Sstevel@tonic-gate static void	scsa1394_cmd_adjust_cdb(scsa1394_lun_t *, scsa1394_cmd_t *);
1457c478bd9Sstevel@tonic-gate static void	scsa1394_cmd_status_wrka(scsa1394_lun_t *, scsa1394_cmd_t *);
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate /* other routines */
1487c478bd9Sstevel@tonic-gate static boolean_t scsa1394_is_my_child(dev_info_t *);
1497c478bd9Sstevel@tonic-gate static void *	scsa1394_kmem_realloc(void *, int, int, size_t, int);
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate static void	*scsa1394_statep;
1527c478bd9Sstevel@tonic-gate #define	SCSA1394_INST2STATE(inst) (ddi_get_soft_state(scsa1394_statep, inst))
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate static struct cb_ops scsa1394_cb_ops = {
1557c478bd9Sstevel@tonic-gate 	nodev,			/* open */
1567c478bd9Sstevel@tonic-gate 	nodev,			/* close */
1577c478bd9Sstevel@tonic-gate 	nodev,			/* strategy */
1587c478bd9Sstevel@tonic-gate 	nodev,			/* print */
1597c478bd9Sstevel@tonic-gate 	nodev,			/* dump */
1607c478bd9Sstevel@tonic-gate 	nodev,			/* read */
1617c478bd9Sstevel@tonic-gate 	nodev,			/* write */
1627c478bd9Sstevel@tonic-gate 	NULL,			/* ioctl */
1637c478bd9Sstevel@tonic-gate 	nodev,			/* devmap */
1647c478bd9Sstevel@tonic-gate 	nodev,			/* mmap */
1657c478bd9Sstevel@tonic-gate 	nodev,			/* segmap */
1667c478bd9Sstevel@tonic-gate 	nochpoll,		/* poll */
1677c478bd9Sstevel@tonic-gate 	ddi_prop_op,		/* prop_op */
1687c478bd9Sstevel@tonic-gate 	NULL,			/* stream */
1697c478bd9Sstevel@tonic-gate 	D_MP,			/* cb_flag */
170f5488aa8Sbharding 	CB_REV,			/* rev */
1717c478bd9Sstevel@tonic-gate 	nodev,			/* aread */
1727c478bd9Sstevel@tonic-gate 	nodev			/* awrite */
1737c478bd9Sstevel@tonic-gate };
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate static struct dev_ops scsa1394_ops = {
1767c478bd9Sstevel@tonic-gate 	DEVO_REV,		/* devo_rev, */
1777c478bd9Sstevel@tonic-gate 	0,			/* refcnt  */
1787c478bd9Sstevel@tonic-gate 	ddi_no_info,		/* info */
1797c478bd9Sstevel@tonic-gate 	nulldev,		/* identify */
1807c478bd9Sstevel@tonic-gate 	nulldev,		/* probe */
1817c478bd9Sstevel@tonic-gate 	scsa1394_attach,	/* attach */
1827c478bd9Sstevel@tonic-gate 	scsa1394_detach,	/* detach */
1837c478bd9Sstevel@tonic-gate 	nodev,			/* reset */
1847c478bd9Sstevel@tonic-gate 	&scsa1394_cb_ops,	/* driver operations */
1857c478bd9Sstevel@tonic-gate 	NULL,			/* bus operations */
18619397407SSherry Moore 	scsa1394_power,		/* power */
18719397407SSherry Moore 	ddi_quiesce_not_supported,	/* devo_quiesce */
1887c478bd9Sstevel@tonic-gate };
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate static struct modldrv scsa1394_modldrv = {
1917c478bd9Sstevel@tonic-gate 	&mod_driverops,			/* module type */
192f5488aa8Sbharding 	"1394 Mass Storage HBA Driver", /* name of the module */
1937c478bd9Sstevel@tonic-gate 	&scsa1394_ops,			/* driver ops */
1947c478bd9Sstevel@tonic-gate };
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate static struct modlinkage scsa1394_modlinkage = {
1977c478bd9Sstevel@tonic-gate 	MODREV_1, (void *)&scsa1394_modldrv, NULL
1987c478bd9Sstevel@tonic-gate };
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate /* tunables */
2017c478bd9Sstevel@tonic-gate int scsa1394_bus_config_debug = 0;
2027c478bd9Sstevel@tonic-gate int scsa1394_start_stop_fail_max = SCSA1394_START_STOP_FAIL_MAX;
2037c478bd9Sstevel@tonic-gate int scsa1394_mode_sense_fail_max = SCSA1394_MODE_SENSE_FAIL_MAX;
2047c478bd9Sstevel@tonic-gate int scsa1394_start_stop_timeout_max = SCSA1394_START_STOP_TIMEOUT_MAX;
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate /* workarounds */
2077c478bd9Sstevel@tonic-gate int scsa1394_wrka_rbc2direct = 1;
2080167b58cScg int scsa1394_wrka_fake_rmb = 0;
2097c478bd9Sstevel@tonic-gate int scsa1394_wrka_fake_prin = 1;
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate int scsa1394_wrka_symbios = 1;
2127c478bd9Sstevel@tonic-gate int scsa1394_symbios_page_size = 4 * 1024;	/* must be <= _pagesize */
2137c478bd9Sstevel@tonic-gate int scsa1394_symbios_size_max = 512 * 248;	/* multiple of page size */
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate /*
2167c478bd9Sstevel@tonic-gate  *
2177c478bd9Sstevel@tonic-gate  * --- DDI/DKI entry points
2187c478bd9Sstevel@tonic-gate  *
2197c478bd9Sstevel@tonic-gate  */
2207c478bd9Sstevel@tonic-gate int
_init(void)2217c478bd9Sstevel@tonic-gate _init(void)
2227c478bd9Sstevel@tonic-gate {
2237c478bd9Sstevel@tonic-gate 	int	ret;
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 	if (((ret = ddi_soft_state_init(&scsa1394_statep,
2267c478bd9Sstevel@tonic-gate 	    sizeof (scsa1394_state_t), 1)) != 0)) {
2277c478bd9Sstevel@tonic-gate 		return (ret);
2287c478bd9Sstevel@tonic-gate 	}
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 	if ((ret = scsi_hba_init(&scsa1394_modlinkage)) != 0) {
2317c478bd9Sstevel@tonic-gate 		ddi_soft_state_fini(&scsa1394_statep);
2327c478bd9Sstevel@tonic-gate 		return (ret);
2337c478bd9Sstevel@tonic-gate 	}
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 	if ((ret = mod_install(&scsa1394_modlinkage)) != 0) {
2367c478bd9Sstevel@tonic-gate 		scsi_hba_fini(&scsa1394_modlinkage);
2377c478bd9Sstevel@tonic-gate 		ddi_soft_state_fini(&scsa1394_statep);
2387c478bd9Sstevel@tonic-gate 		return (ret);
2397c478bd9Sstevel@tonic-gate 	}
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate 	return (ret);
2427c478bd9Sstevel@tonic-gate }
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate int
_fini(void)2457c478bd9Sstevel@tonic-gate _fini(void)
2467c478bd9Sstevel@tonic-gate {
2477c478bd9Sstevel@tonic-gate 	int	ret;
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 	if ((ret = mod_remove(&scsa1394_modlinkage)) == 0) {
2507c478bd9Sstevel@tonic-gate 		scsi_hba_fini(&scsa1394_modlinkage);
2517c478bd9Sstevel@tonic-gate 		ddi_soft_state_fini(&scsa1394_statep);
2527c478bd9Sstevel@tonic-gate 	}
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate 	return (ret);
2557c478bd9Sstevel@tonic-gate }
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)2587c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
2597c478bd9Sstevel@tonic-gate {
2607c478bd9Sstevel@tonic-gate 	return (mod_info(&scsa1394_modlinkage, modinfop));
2617c478bd9Sstevel@tonic-gate }
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate static int
scsa1394_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)2647c478bd9Sstevel@tonic-gate scsa1394_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2657c478bd9Sstevel@tonic-gate {
2667c478bd9Sstevel@tonic-gate 	int		instance = ddi_get_instance(dip);
2677c478bd9Sstevel@tonic-gate 	scsa1394_state_t *sp;
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate 	switch (cmd) {
2707c478bd9Sstevel@tonic-gate 	case DDI_ATTACH:
2717c478bd9Sstevel@tonic-gate 		break;
2727c478bd9Sstevel@tonic-gate 	case DDI_RESUME:
273f5488aa8Sbharding 		scsa1394_cpr_resume(dip);
2747c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
2757c478bd9Sstevel@tonic-gate 	default:
2767c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2777c478bd9Sstevel@tonic-gate 	}
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate 	if (ddi_soft_state_zalloc(scsa1394_statep, instance) != 0) {
2807c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2817c478bd9Sstevel@tonic-gate 	}
2827c478bd9Sstevel@tonic-gate 	sp = SCSA1394_INST2STATE(instance);
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate #ifndef __lock_lint
2857c478bd9Sstevel@tonic-gate 	sp->s_dip = dip;
2867c478bd9Sstevel@tonic-gate 	sp->s_instance = instance;
2877c478bd9Sstevel@tonic-gate #endif
2887c478bd9Sstevel@tonic-gate 	mutex_init(&sp->s_mutex, NULL, MUTEX_DRIVER,
2897c478bd9Sstevel@tonic-gate 	    sp->s_attachinfo.iblock_cookie);
2907c478bd9Sstevel@tonic-gate 	cv_init(&sp->s_event_cv, NULL, CV_DRIVER, NULL);
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	if (scsa1394_attach_1394(sp) != DDI_SUCCESS) {
2937c478bd9Sstevel@tonic-gate 		scsa1394_cleanup(sp, 1);
2947c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
2957c478bd9Sstevel@tonic-gate 	}
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 	if (scsa1394_sbp2_attach(sp) != DDI_SUCCESS) {
2987c478bd9Sstevel@tonic-gate 		scsa1394_cleanup(sp, 2);
2997c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
3007c478bd9Sstevel@tonic-gate 	}
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate 	if (scsa1394_attach_threads(sp) != DDI_SUCCESS) {
3037c478bd9Sstevel@tonic-gate 		scsa1394_cleanup(sp, 3);
3047c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
3057c478bd9Sstevel@tonic-gate 	}
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	if (scsa1394_attach_scsa(sp) != DDI_SUCCESS) {
3087c478bd9Sstevel@tonic-gate 		scsa1394_cleanup(sp, 4);
3097c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
3107c478bd9Sstevel@tonic-gate 	}
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	if (scsa1394_create_cmd_cache(sp) != DDI_SUCCESS) {
3137c478bd9Sstevel@tonic-gate 		scsa1394_cleanup(sp, 5);
3147c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
3157c478bd9Sstevel@tonic-gate 	}
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate 	if (scsa1394_add_events(sp) != DDI_SUCCESS) {
3187c478bd9Sstevel@tonic-gate 		scsa1394_cleanup(sp, 6);
3197c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
3207c478bd9Sstevel@tonic-gate 	}
3217c478bd9Sstevel@tonic-gate 
322f5488aa8Sbharding 	/* prevent async PM changes until we are done */
323f5488aa8Sbharding 	(void) pm_busy_component(dip, 0);
324f5488aa8Sbharding 
325f5488aa8Sbharding 	/* Set power to full on */
326f5488aa8Sbharding 	(void) pm_raise_power(dip, 0, PM_LEVEL_D0);
327f5488aa8Sbharding 
328f5488aa8Sbharding 	/* we are done */
329f5488aa8Sbharding 	(void) pm_idle_component(dip, 0);
330f5488aa8Sbharding 
3317c478bd9Sstevel@tonic-gate #ifndef __lock_lint
3327c478bd9Sstevel@tonic-gate 	sp->s_dev_state = SCSA1394_DEV_ONLINE;
3337c478bd9Sstevel@tonic-gate #endif
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 	ddi_report_dev(dip);
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
3387c478bd9Sstevel@tonic-gate }
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate static int
scsa1394_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)3417c478bd9Sstevel@tonic-gate scsa1394_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
3427c478bd9Sstevel@tonic-gate {
3437c478bd9Sstevel@tonic-gate 	int		instance = ddi_get_instance(dip);
3447c478bd9Sstevel@tonic-gate 	scsa1394_state_t *sp;
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 	if ((sp = SCSA1394_INST2STATE(instance)) == NULL) {
3477c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
3487c478bd9Sstevel@tonic-gate 	}
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 	switch (cmd) {
3517c478bd9Sstevel@tonic-gate 	case DDI_DETACH:
352f5488aa8Sbharding 		/* Cycle power state to off and idle  where done/gone */
353f5488aa8Sbharding 		(void) pm_lower_power(dip, 0, PM_LEVEL_D3);
354f5488aa8Sbharding 
3557c478bd9Sstevel@tonic-gate 		scsa1394_cleanup(sp, SCSA1394_CLEANUP_LEVEL_MAX);
3567c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
3577c478bd9Sstevel@tonic-gate 	case DDI_SUSPEND:
358f5488aa8Sbharding 		return (scsa1394_cpr_suspend(dip));
3597c478bd9Sstevel@tonic-gate 	default:
3607c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
3617c478bd9Sstevel@tonic-gate 	}
3627c478bd9Sstevel@tonic-gate }
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate /*ARGSUSED*/
3657c478bd9Sstevel@tonic-gate static int
scsa1394_power(dev_info_t * dip,int comp,int level)3667c478bd9Sstevel@tonic-gate scsa1394_power(dev_info_t *dip, int comp, int level)
3677c478bd9Sstevel@tonic-gate {
3687c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
3697c478bd9Sstevel@tonic-gate }
3707c478bd9Sstevel@tonic-gate 
371f5488aa8Sbharding /*
372f5488aa8Sbharding  * scsa1394_cpr_suspend
373f5488aa8Sbharding  *	determine if the device's state can be changed to SUSPENDED
374f5488aa8Sbharding  */
375f5488aa8Sbharding /* ARGSUSED */
376f5488aa8Sbharding static int
scsa1394_cpr_suspend(dev_info_t * dip)377f5488aa8Sbharding scsa1394_cpr_suspend(dev_info_t *dip)
378f5488aa8Sbharding {
379f5488aa8Sbharding 	int		instance = ddi_get_instance(dip);
380f5488aa8Sbharding 	scsa1394_state_t *sp;
381f5488aa8Sbharding 	int		rval = DDI_FAILURE;
382f5488aa8Sbharding 
383f5488aa8Sbharding 	sp = SCSA1394_INST2STATE(instance);
384f5488aa8Sbharding 
385f5488aa8Sbharding 	ASSERT(sp != NULL);
386f5488aa8Sbharding 
387f5488aa8Sbharding 
388f5488aa8Sbharding 	mutex_enter(&sp->s_mutex);
389f5488aa8Sbharding 	switch (sp->s_dev_state) {
390f5488aa8Sbharding 	case SCSA1394_DEV_ONLINE:
391f5488aa8Sbharding 	case SCSA1394_DEV_PWRED_DOWN:
392f5488aa8Sbharding 	case SCSA1394_DEV_DISCONNECTED:
393f5488aa8Sbharding 		sp->s_dev_state = SCSA1394_DEV_SUSPENDED;
394f5488aa8Sbharding 
395f5488aa8Sbharding 		/*  Power down and make device idle */
396f5488aa8Sbharding 		(void) pm_lower_power(dip, 0, PM_LEVEL_D3);
397f5488aa8Sbharding 
398f5488aa8Sbharding 		rval = DDI_SUCCESS;
399f5488aa8Sbharding 		break;
400f5488aa8Sbharding 	case SCSA1394_DEV_SUSPENDED:
401f5488aa8Sbharding 	default:
402f5488aa8Sbharding 		if (scsa1394_bus_config_debug)
403f5488aa8Sbharding 			cmn_err(CE_WARN,
404f5488aa8Sbharding 			    "scsa1304_cpr_suspend: Illegal dev state: %d",
405f5488aa8Sbharding 			    sp->s_dev_state);
406f5488aa8Sbharding 
407f5488aa8Sbharding 		rval = DDI_SUCCESS;
408f5488aa8Sbharding 		break;
409f5488aa8Sbharding 	}
410f5488aa8Sbharding 	mutex_exit(&sp->s_mutex);
411f5488aa8Sbharding 
412f5488aa8Sbharding 	return (rval);
413f5488aa8Sbharding }
414f5488aa8Sbharding 
415f5488aa8Sbharding /*
416f5488aa8Sbharding  * scsa2usb_cpr_resume:
417f5488aa8Sbharding  *	restore device's state
418f5488aa8Sbharding  */
419f5488aa8Sbharding static void
scsa1394_cpr_resume(dev_info_t * dip)420f5488aa8Sbharding scsa1394_cpr_resume(dev_info_t *dip)
421f5488aa8Sbharding {
422f5488aa8Sbharding 	int		instance = ddi_get_instance(dip);
423f5488aa8Sbharding 	scsa1394_state_t *sp;
424f5488aa8Sbharding 	int		i;
425f5488aa8Sbharding 	scsa1394_lun_t	*lp;
426f5488aa8Sbharding 
427f5488aa8Sbharding 	sp = SCSA1394_INST2STATE(instance);
428f5488aa8Sbharding 
429f5488aa8Sbharding 	ASSERT(sp != NULL);
430f5488aa8Sbharding 
431f5488aa8Sbharding 	if (sp->s_dev_state != SCSA1394_DEV_SUSPENDED)
432f5488aa8Sbharding 		return;
433f5488aa8Sbharding 
434f5488aa8Sbharding 	/*
435f5488aa8Sbharding 	 * Go through each lun and reset it to force a reconnect.
436f5488aa8Sbharding 	 */
437f5488aa8Sbharding 	for (i = 0; i < sp->s_nluns; i++) {
438f5488aa8Sbharding 		lp = &sp->s_lun[i];
439f5488aa8Sbharding 		if (lp->l_ses != NULL) {  /* Are we loged in? */
440f5488aa8Sbharding 			scsa1394_sbp2_req_bus_reset(lp);
441f5488aa8Sbharding 			scsa1394_sbp2_req_reconnect(lp);
442f5488aa8Sbharding 		}
443f5488aa8Sbharding 	}
444f5488aa8Sbharding 
445f5488aa8Sbharding 	/* we are down so let the power get managed */
446f5488aa8Sbharding 	(void) pm_idle_component(dip, 0);
447f5488aa8Sbharding }
448f5488aa8Sbharding 
449f5488aa8Sbharding 
450f5488aa8Sbharding 
4517c478bd9Sstevel@tonic-gate /*
4527c478bd9Sstevel@tonic-gate  *
4537c478bd9Sstevel@tonic-gate  * --- configuration routines
4547c478bd9Sstevel@tonic-gate  *
4557c478bd9Sstevel@tonic-gate  */
4567c478bd9Sstevel@tonic-gate static void
scsa1394_cleanup(scsa1394_state_t * sp,int level)4577c478bd9Sstevel@tonic-gate scsa1394_cleanup(scsa1394_state_t *sp, int level)
4587c478bd9Sstevel@tonic-gate {
4597c478bd9Sstevel@tonic-gate 	ASSERT((level > 0) && (level <= SCSA1394_CLEANUP_LEVEL_MAX));
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate 	switch (level) {
4627c478bd9Sstevel@tonic-gate 	default:
4637c478bd9Sstevel@tonic-gate 		scsa1394_remove_events(sp);
4647c478bd9Sstevel@tonic-gate 		/* FALLTHRU */
4657c478bd9Sstevel@tonic-gate 	case 6:
4667c478bd9Sstevel@tonic-gate 		scsa1394_detach_scsa(sp);
4677c478bd9Sstevel@tonic-gate 		/* FALLTHRU */
4687c478bd9Sstevel@tonic-gate 	case 5:
4697c478bd9Sstevel@tonic-gate 		scsa1394_destroy_cmd_cache(sp);
4707c478bd9Sstevel@tonic-gate 		/* FALLTHRU */
4717c478bd9Sstevel@tonic-gate 	case 4:
4727c478bd9Sstevel@tonic-gate 		scsa1394_detach_threads(sp);
4737c478bd9Sstevel@tonic-gate 		/* FALLTHRU */
4747c478bd9Sstevel@tonic-gate 	case 3:
4757c478bd9Sstevel@tonic-gate 		scsa1394_sbp2_detach(sp);
4767c478bd9Sstevel@tonic-gate 		/* FALLTHRU */
4777c478bd9Sstevel@tonic-gate 	case 2:
4787c478bd9Sstevel@tonic-gate 		scsa1394_detach_1394(sp);
4797c478bd9Sstevel@tonic-gate 		/* FALLTHRU */
4807c478bd9Sstevel@tonic-gate 	case 1:
4817c478bd9Sstevel@tonic-gate 		cv_destroy(&sp->s_event_cv);
4827c478bd9Sstevel@tonic-gate 		mutex_destroy(&sp->s_mutex);
4837c478bd9Sstevel@tonic-gate 		ddi_soft_state_free(scsa1394_statep, sp->s_instance);
4847c478bd9Sstevel@tonic-gate 	}
4857c478bd9Sstevel@tonic-gate }
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate static int
scsa1394_attach_1394(scsa1394_state_t * sp)4887c478bd9Sstevel@tonic-gate scsa1394_attach_1394(scsa1394_state_t *sp)
4897c478bd9Sstevel@tonic-gate {
4907c478bd9Sstevel@tonic-gate 	int	ret;
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate 	if ((ret = t1394_attach(sp->s_dip, T1394_VERSION_V1, 0,
4937c478bd9Sstevel@tonic-gate 	    &sp->s_attachinfo, &sp->s_t1394_hdl)) != DDI_SUCCESS) {
4947c478bd9Sstevel@tonic-gate 		return (ret);
4957c478bd9Sstevel@tonic-gate 	}
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	/* DMA attributes for data buffers */
4987c478bd9Sstevel@tonic-gate 	sp->s_buf_dma_attr = sp->s_attachinfo.dma_attr;
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate 	/* DMA attributes for page tables */
5017c478bd9Sstevel@tonic-gate 	sp->s_pt_dma_attr = sp->s_attachinfo.dma_attr;
5027c478bd9Sstevel@tonic-gate 	sp->s_pt_dma_attr.dma_attr_sgllen = 1;	/* pt must be contiguous */
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate 	if ((ret = t1394_get_targetinfo(sp->s_t1394_hdl, SCSA1394_BUSGEN(sp), 0,
5057c478bd9Sstevel@tonic-gate 	    &sp->s_targetinfo)) != DDI_SUCCESS) {
5067c478bd9Sstevel@tonic-gate 		(void) t1394_detach(&sp->s_t1394_hdl, 0);
5077c478bd9Sstevel@tonic-gate 		return (ret);
5087c478bd9Sstevel@tonic-gate 	}
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
5117c478bd9Sstevel@tonic-gate }
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate static void
scsa1394_detach_1394(scsa1394_state_t * sp)5147c478bd9Sstevel@tonic-gate scsa1394_detach_1394(scsa1394_state_t *sp)
5157c478bd9Sstevel@tonic-gate {
5167c478bd9Sstevel@tonic-gate 	(void) t1394_detach(&sp->s_t1394_hdl, 0);
5177c478bd9Sstevel@tonic-gate }
5187c478bd9Sstevel@tonic-gate 
5197c478bd9Sstevel@tonic-gate static int
scsa1394_attach_threads(scsa1394_state_t * sp)5207c478bd9Sstevel@tonic-gate scsa1394_attach_threads(scsa1394_state_t *sp)
5217c478bd9Sstevel@tonic-gate {
5227c478bd9Sstevel@tonic-gate 	char		name[16];
5237c478bd9Sstevel@tonic-gate 	int		nthr;
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate 	nthr = sp->s_nluns;
5267c478bd9Sstevel@tonic-gate 	(void) snprintf(name, sizeof (name), "scsa1394%d", sp->s_instance);
5277c478bd9Sstevel@tonic-gate 	if ((sp->s_taskq = ddi_taskq_create(sp->s_dip, name, nthr,
5287c478bd9Sstevel@tonic-gate 	    TASKQ_DEFAULTPRI, 0)) == NULL) {
5297c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
5307c478bd9Sstevel@tonic-gate 	}
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate 	if (scsa1394_sbp2_threads_init(sp) != DDI_SUCCESS) {
5337c478bd9Sstevel@tonic-gate 		ddi_taskq_destroy(sp->s_taskq);
5347c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
5357c478bd9Sstevel@tonic-gate 	}
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
5387c478bd9Sstevel@tonic-gate }
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate static void
scsa1394_detach_threads(scsa1394_state_t * sp)5417c478bd9Sstevel@tonic-gate scsa1394_detach_threads(scsa1394_state_t *sp)
5427c478bd9Sstevel@tonic-gate {
5437c478bd9Sstevel@tonic-gate 	scsa1394_sbp2_threads_fini(sp);
5447c478bd9Sstevel@tonic-gate 	ddi_taskq_destroy(sp->s_taskq);
5457c478bd9Sstevel@tonic-gate }
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate static int
scsa1394_attach_scsa(scsa1394_state_t * sp)5487c478bd9Sstevel@tonic-gate scsa1394_attach_scsa(scsa1394_state_t *sp)
5497c478bd9Sstevel@tonic-gate {
5507c478bd9Sstevel@tonic-gate 	scsi_hba_tran_t	*tran;
5517c478bd9Sstevel@tonic-gate 	int		ret;
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate 	sp->s_tran = tran = scsi_hba_tran_alloc(sp->s_dip, SCSI_HBA_CANSLEEP);
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate 	tran->tran_hba_private	= sp;
5567c478bd9Sstevel@tonic-gate 	tran->tran_tgt_private	= NULL;
5577c478bd9Sstevel@tonic-gate 	tran->tran_tgt_init	= scsa1394_scsi_tgt_init;
5587c478bd9Sstevel@tonic-gate 	tran->tran_tgt_probe	= scsa1394_scsi_tgt_probe;
5597c478bd9Sstevel@tonic-gate 	tran->tran_tgt_free	= scsa1394_scsi_tgt_free;
5607c478bd9Sstevel@tonic-gate 	tran->tran_start	= scsa1394_scsi_start;
5617c478bd9Sstevel@tonic-gate 	tran->tran_abort	= scsa1394_scsi_abort;
5627c478bd9Sstevel@tonic-gate 	tran->tran_reset	= scsa1394_scsi_reset;
5637c478bd9Sstevel@tonic-gate 	tran->tran_getcap	= scsa1394_scsi_getcap;
5647c478bd9Sstevel@tonic-gate 	tran->tran_setcap	= scsa1394_scsi_setcap;
5657c478bd9Sstevel@tonic-gate 	tran->tran_init_pkt	= scsa1394_scsi_init_pkt;
5667c478bd9Sstevel@tonic-gate 	tran->tran_destroy_pkt	= scsa1394_scsi_destroy_pkt;
5677c478bd9Sstevel@tonic-gate 	tran->tran_dmafree	= scsa1394_scsi_dmafree;
5687c478bd9Sstevel@tonic-gate 	tran->tran_sync_pkt	= scsa1394_scsi_sync_pkt;
5697c478bd9Sstevel@tonic-gate 	tran->tran_reset_notify	= NULL;
5707c478bd9Sstevel@tonic-gate 	tran->tran_get_bus_addr	= NULL;
5717c478bd9Sstevel@tonic-gate 	tran->tran_get_name	= NULL;
5727c478bd9Sstevel@tonic-gate 	tran->tran_bus_reset	= NULL;
5737c478bd9Sstevel@tonic-gate 	tran->tran_quiesce	= NULL;
5747c478bd9Sstevel@tonic-gate 	tran->tran_unquiesce	= NULL;
5757c478bd9Sstevel@tonic-gate 	tran->tran_get_eventcookie = NULL;
5767c478bd9Sstevel@tonic-gate 	tran->tran_add_eventcall = NULL;
5777c478bd9Sstevel@tonic-gate 	tran->tran_remove_eventcall = NULL;
5787c478bd9Sstevel@tonic-gate 	tran->tran_post_event	= NULL;
5797c478bd9Sstevel@tonic-gate 	tran->tran_bus_config	= scsa1394_scsi_bus_config;
5807c478bd9Sstevel@tonic-gate 	tran->tran_bus_unconfig	= scsa1394_scsi_bus_unconfig;
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate 	if ((ret = scsi_hba_attach_setup(sp->s_dip, &sp->s_attachinfo.dma_attr,
5837c478bd9Sstevel@tonic-gate 	    tran, 0)) != DDI_SUCCESS) {
5847c478bd9Sstevel@tonic-gate 		scsi_hba_tran_free(tran);
5857c478bd9Sstevel@tonic-gate 		return (ret);
5867c478bd9Sstevel@tonic-gate 	}
5877c478bd9Sstevel@tonic-gate 
5887c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
5897c478bd9Sstevel@tonic-gate }
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate static void
scsa1394_detach_scsa(scsa1394_state_t * sp)5927c478bd9Sstevel@tonic-gate scsa1394_detach_scsa(scsa1394_state_t *sp)
5937c478bd9Sstevel@tonic-gate {
5947c478bd9Sstevel@tonic-gate 	int	ret;
5957c478bd9Sstevel@tonic-gate 
5967c478bd9Sstevel@tonic-gate 	ret = scsi_hba_detach(sp->s_dip);
5977c478bd9Sstevel@tonic-gate 	ASSERT(ret == DDI_SUCCESS);
5987c478bd9Sstevel@tonic-gate 
5997c478bd9Sstevel@tonic-gate 	scsi_hba_tran_free(sp->s_tran);
6007c478bd9Sstevel@tonic-gate }
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate static int
scsa1394_create_cmd_cache(scsa1394_state_t * sp)6037c478bd9Sstevel@tonic-gate scsa1394_create_cmd_cache(scsa1394_state_t *sp)
6047c478bd9Sstevel@tonic-gate {
6057c478bd9Sstevel@tonic-gate 	char	name[64];
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate 	(void) sprintf(name, "scsa1394%d_cache", sp->s_instance);
6087c478bd9Sstevel@tonic-gate 	sp->s_cmd_cache = kmem_cache_create(name,
609602ca9eaScth 	    SCSA1394_CMD_SIZE, sizeof (void *),
6107c478bd9Sstevel@tonic-gate 	    scsa1394_cmd_cache_constructor, scsa1394_cmd_cache_destructor,
6117c478bd9Sstevel@tonic-gate 	    NULL, (void *)sp, NULL, 0);
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate 	return ((sp->s_cmd_cache == NULL) ? DDI_FAILURE : DDI_SUCCESS);
6147c478bd9Sstevel@tonic-gate }
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate static void
scsa1394_destroy_cmd_cache(scsa1394_state_t * sp)6177c478bd9Sstevel@tonic-gate scsa1394_destroy_cmd_cache(scsa1394_state_t *sp)
6187c478bd9Sstevel@tonic-gate {
6197c478bd9Sstevel@tonic-gate 	kmem_cache_destroy(sp->s_cmd_cache);
6207c478bd9Sstevel@tonic-gate }
6217c478bd9Sstevel@tonic-gate 
6227c478bd9Sstevel@tonic-gate static int
scsa1394_add_events(scsa1394_state_t * sp)6237c478bd9Sstevel@tonic-gate scsa1394_add_events(scsa1394_state_t *sp)
6247c478bd9Sstevel@tonic-gate {
6257c478bd9Sstevel@tonic-gate 	ddi_eventcookie_t	br_evc, rem_evc, ins_evc;
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate 	if (ddi_get_eventcookie(sp->s_dip, DDI_DEVI_BUS_RESET_EVENT,
6287c478bd9Sstevel@tonic-gate 	    &br_evc) != DDI_SUCCESS) {
6297c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6307c478bd9Sstevel@tonic-gate 	}
6317c478bd9Sstevel@tonic-gate 	if (ddi_add_event_handler(sp->s_dip, br_evc, scsa1394_bus_reset,
6327c478bd9Sstevel@tonic-gate 	    sp, &sp->s_reset_cb_id) != DDI_SUCCESS) {
6337c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6347c478bd9Sstevel@tonic-gate 	}
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 	if (ddi_get_eventcookie(sp->s_dip, DDI_DEVI_REMOVE_EVENT,
6377c478bd9Sstevel@tonic-gate 	    &rem_evc) != DDI_SUCCESS) {
6387c478bd9Sstevel@tonic-gate 		(void) ddi_remove_event_handler(sp->s_reset_cb_id);
6397c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6407c478bd9Sstevel@tonic-gate 	}
6417c478bd9Sstevel@tonic-gate 	if (ddi_add_event_handler(sp->s_dip, rem_evc, scsa1394_disconnect,
6427c478bd9Sstevel@tonic-gate 	    sp, &sp->s_remove_cb_id) != DDI_SUCCESS) {
6437c478bd9Sstevel@tonic-gate 		(void) ddi_remove_event_handler(sp->s_reset_cb_id);
6447c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6457c478bd9Sstevel@tonic-gate 	}
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate 	if (ddi_get_eventcookie(sp->s_dip, DDI_DEVI_INSERT_EVENT,
6487c478bd9Sstevel@tonic-gate 	    &ins_evc) != DDI_SUCCESS) {
6497c478bd9Sstevel@tonic-gate 		(void) ddi_remove_event_handler(sp->s_remove_cb_id);
6507c478bd9Sstevel@tonic-gate 		(void) ddi_remove_event_handler(sp->s_reset_cb_id);
6517c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6527c478bd9Sstevel@tonic-gate 	}
6537c478bd9Sstevel@tonic-gate 	if (ddi_add_event_handler(sp->s_dip, ins_evc, scsa1394_reconnect,
6547c478bd9Sstevel@tonic-gate 	    sp, &sp->s_insert_cb_id) != DDI_SUCCESS) {
6557c478bd9Sstevel@tonic-gate 		(void) ddi_remove_event_handler(sp->s_remove_cb_id);
6567c478bd9Sstevel@tonic-gate 		(void) ddi_remove_event_handler(sp->s_reset_cb_id);
6577c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6587c478bd9Sstevel@tonic-gate 	}
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
6617c478bd9Sstevel@tonic-gate }
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate static void
scsa1394_remove_events(scsa1394_state_t * sp)6647c478bd9Sstevel@tonic-gate scsa1394_remove_events(scsa1394_state_t *sp)
6657c478bd9Sstevel@tonic-gate {
6667c478bd9Sstevel@tonic-gate 	ddi_eventcookie_t	evc;
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate 	if (ddi_get_eventcookie(sp->s_dip, DDI_DEVI_INSERT_EVENT,
6697c478bd9Sstevel@tonic-gate 	    &evc) == DDI_SUCCESS) {
6707c478bd9Sstevel@tonic-gate 		(void) ddi_remove_event_handler(sp->s_insert_cb_id);
6717c478bd9Sstevel@tonic-gate 	}
6727c478bd9Sstevel@tonic-gate 
6737c478bd9Sstevel@tonic-gate 	if (ddi_get_eventcookie(sp->s_dip, DDI_DEVI_REMOVE_EVENT,
6747c478bd9Sstevel@tonic-gate 	    &evc) == DDI_SUCCESS) {
6757c478bd9Sstevel@tonic-gate 		(void) ddi_remove_event_handler(sp->s_remove_cb_id);
6767c478bd9Sstevel@tonic-gate 	}
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate 	if (ddi_get_eventcookie(sp->s_dip, DDI_DEVI_BUS_RESET_EVENT,
6797c478bd9Sstevel@tonic-gate 	    &evc) == DDI_SUCCESS) {
6807c478bd9Sstevel@tonic-gate 		(void) ddi_remove_event_handler(sp->s_reset_cb_id);
6817c478bd9Sstevel@tonic-gate 	}
6827c478bd9Sstevel@tonic-gate }
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate /*
6857c478bd9Sstevel@tonic-gate  *
6867c478bd9Sstevel@tonic-gate  * --- device configuration
6877c478bd9Sstevel@tonic-gate  *
6887c478bd9Sstevel@tonic-gate  */
6897c478bd9Sstevel@tonic-gate static int
scsa1394_scsi_bus_config(dev_info_t * dip,uint_t flag,ddi_bus_config_op_t op,void * arg,dev_info_t ** child)6907c478bd9Sstevel@tonic-gate scsa1394_scsi_bus_config(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op,
6917c478bd9Sstevel@tonic-gate     void *arg, dev_info_t **child)
6927c478bd9Sstevel@tonic-gate {
6937c478bd9Sstevel@tonic-gate 	scsa1394_state_t *sp = SCSA1394_INST2STATE(ddi_get_instance(dip));
6947c478bd9Sstevel@tonic-gate 	int		ret;
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate 	if (scsa1394_bus_config_debug) {
6977c478bd9Sstevel@tonic-gate 		flag |= NDI_DEVI_DEBUG;
6987c478bd9Sstevel@tonic-gate 	}
6997c478bd9Sstevel@tonic-gate 
700*3fe80ca4SDan Cross 	ndi_devi_enter(dip);
7017c478bd9Sstevel@tonic-gate 	if (DEVI(dip)->devi_child == NULL) {
7027c478bd9Sstevel@tonic-gate 		scsa1394_create_children(sp);
7037c478bd9Sstevel@tonic-gate 	}
7047c478bd9Sstevel@tonic-gate 	ret = ndi_busop_bus_config(dip, flag, op, arg, child, 0);
705*3fe80ca4SDan Cross 	ndi_devi_exit(dip);
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate 	return (ret);
7087c478bd9Sstevel@tonic-gate }
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate static int
scsa1394_scsi_bus_unconfig(dev_info_t * dip,uint_t flag,ddi_bus_config_op_t op,void * arg)7117c478bd9Sstevel@tonic-gate scsa1394_scsi_bus_unconfig(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op,
7127c478bd9Sstevel@tonic-gate     void *arg)
7137c478bd9Sstevel@tonic-gate {
7147c478bd9Sstevel@tonic-gate 	scsa1394_state_t *sp = SCSA1394_INST2STATE(ddi_get_instance(dip));
7157c478bd9Sstevel@tonic-gate 	int		ret;
7167c478bd9Sstevel@tonic-gate 	uint_t		saved_flag = flag;
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate 	if (scsa1394_bus_config_debug) {
7197c478bd9Sstevel@tonic-gate 		flag |= NDI_DEVI_DEBUG;
7207c478bd9Sstevel@tonic-gate 	}
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate 	/*
7237c478bd9Sstevel@tonic-gate 	 * First offline and if offlining successful, then remove children.
7247c478bd9Sstevel@tonic-gate 	 */
7257c478bd9Sstevel@tonic-gate 	if (op == BUS_UNCONFIG_ALL) {
7267c478bd9Sstevel@tonic-gate 		flag &= ~(NDI_DEVI_REMOVE | NDI_UNCONFIG);
7277c478bd9Sstevel@tonic-gate 	}
7287c478bd9Sstevel@tonic-gate 
729*3fe80ca4SDan Cross 	ndi_devi_enter(dip);
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate 	ret = ndi_busop_bus_unconfig(dip, flag, op, arg);
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate 	/*
7347c478bd9Sstevel@tonic-gate 	 * If previous step was successful and not part of modunload daemon,
7357c478bd9Sstevel@tonic-gate 	 * attempt to remove children.
7367c478bd9Sstevel@tonic-gate 	 */
7377c478bd9Sstevel@tonic-gate 	if ((op == BUS_UNCONFIG_ALL) && (ret == NDI_SUCCESS) &&
7387c478bd9Sstevel@tonic-gate 	    ((flag & NDI_AUTODETACH) == 0)) {
7397c478bd9Sstevel@tonic-gate 		flag |= NDI_DEVI_REMOVE;
7407c478bd9Sstevel@tonic-gate 		ret = ndi_busop_bus_unconfig(dip, flag, op, arg);
7417c478bd9Sstevel@tonic-gate 	}
742*3fe80ca4SDan Cross 	ndi_devi_exit(dip);
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate 	if ((ret != NDI_SUCCESS) && (op == BUS_UNCONFIG_ALL) &&
7457c478bd9Sstevel@tonic-gate 	    ((saved_flag & NDI_DEVI_REMOVE) != 0)) {
7467c478bd9Sstevel@tonic-gate 		mutex_enter(&sp->s_mutex);
7477c478bd9Sstevel@tonic-gate 		if (!sp->s_disconnect_warned) {
7487c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "scsa1394(%d): "
7497c478bd9Sstevel@tonic-gate 			    "Disconnected device was busy, please reconnect.\n",
7507c478bd9Sstevel@tonic-gate 			    sp->s_instance);
7517c478bd9Sstevel@tonic-gate 			sp->s_disconnect_warned = B_TRUE;
7527c478bd9Sstevel@tonic-gate 		}
7537c478bd9Sstevel@tonic-gate 		mutex_exit(&sp->s_mutex);
7547c478bd9Sstevel@tonic-gate 	}
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate 	return (ret);
7577c478bd9Sstevel@tonic-gate }
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate void
scsa1394_dtype2name(int dtype,char ** node_name,char ** driver_name)7607c478bd9Sstevel@tonic-gate scsa1394_dtype2name(int dtype, char **node_name, char **driver_name)
7617c478bd9Sstevel@tonic-gate {
7627c478bd9Sstevel@tonic-gate 	static struct {
7637c478bd9Sstevel@tonic-gate 		char	*node_name;
7647c478bd9Sstevel@tonic-gate 		char	*driver_name;
7657c478bd9Sstevel@tonic-gate 	} dtype2name[] = {
7667c478bd9Sstevel@tonic-gate 		{ "disk",	"sd" },		/* DTYPE_DIRECT		0x00 */
7677c478bd9Sstevel@tonic-gate 		{ "tape",	"st" },		/* DTYPE_SEQUENTIAL	0x01 */
7687c478bd9Sstevel@tonic-gate 		{ "printer",	NULL },		/* DTYPE_PRINTER	0x02 */
7697c478bd9Sstevel@tonic-gate 		{ "processor",	NULL },		/* DTYPE_PROCESSOR	0x03 */
7707c478bd9Sstevel@tonic-gate 		{ "worm",	NULL },		/* DTYPE_WORM		0x04 */
7717c478bd9Sstevel@tonic-gate 		{ "disk",	"sd" },		/* DTYPE_RODIRECT	0x05 */
7727c478bd9Sstevel@tonic-gate 		{ "scanner",	NULL },		/* DTYPE_SCANNER	0x06 */
7737c478bd9Sstevel@tonic-gate 		{ "disk",	"sd" },		/* DTYPE_OPTICAL	0x07 */
7747c478bd9Sstevel@tonic-gate 		{ "changer",	NULL },		/* DTYPE_CHANGER	0x08 */
7757c478bd9Sstevel@tonic-gate 		{ "comm",	NULL },		/* DTYPE_COMM		0x09 */
7767c478bd9Sstevel@tonic-gate 		{ "generic",	NULL },		/* DTYPE_???		0x0A */
7777c478bd9Sstevel@tonic-gate 		{ "generic",	NULL },		/* DTYPE_???		0x0B */
7787c478bd9Sstevel@tonic-gate 		{ "array_ctrl",	NULL },		/* DTYPE_ARRAY_CTRL	0x0C */
779f5488aa8Sbharding 		{ "esi",	"ses" },	/* DTYPE_ESI		0x0D */
7807c478bd9Sstevel@tonic-gate 		{ "disk",	"sd" }		/* DTYPE_RBC		0x0E */
7817c478bd9Sstevel@tonic-gate 	};
7827c478bd9Sstevel@tonic-gate 
7837c478bd9Sstevel@tonic-gate 	if (dtype < NELEM(dtype2name)) {
7847c478bd9Sstevel@tonic-gate 		*node_name = dtype2name[dtype].node_name;
7857c478bd9Sstevel@tonic-gate 		*driver_name = dtype2name[dtype].driver_name;
7867c478bd9Sstevel@tonic-gate 	} else {
7877c478bd9Sstevel@tonic-gate 		*node_name = "generic";
7887c478bd9Sstevel@tonic-gate 		*driver_name = NULL;
7897c478bd9Sstevel@tonic-gate 	}
7907c478bd9Sstevel@tonic-gate }
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate static void
scsa1394_create_children(scsa1394_state_t * sp)7937c478bd9Sstevel@tonic-gate scsa1394_create_children(scsa1394_state_t *sp)
7947c478bd9Sstevel@tonic-gate {
7957c478bd9Sstevel@tonic-gate 	char		name[SCSA1394_COMPAT_MAX][16];
7967c478bd9Sstevel@tonic-gate 	char		*compatible[SCSA1394_COMPAT_MAX];
7977c478bd9Sstevel@tonic-gate 	dev_info_t	*cdip;
7987c478bd9Sstevel@tonic-gate 	int		i;
7997c478bd9Sstevel@tonic-gate 	int		dtype;
8007c478bd9Sstevel@tonic-gate 	char		*node_name;
8017c478bd9Sstevel@tonic-gate 	char		*driver_name;
8027c478bd9Sstevel@tonic-gate 	int		ret;
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate 	bzero(name, sizeof (name));
8057c478bd9Sstevel@tonic-gate 	(void) strcpy(name[0], "sd");
8067c478bd9Sstevel@tonic-gate 	for (i = 0; i < SCSA1394_COMPAT_MAX; i++) {
8077c478bd9Sstevel@tonic-gate 		compatible[i] = name[i];
8087c478bd9Sstevel@tonic-gate 	}
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate 	for (i = 0; i < sp->s_nluns; i++) {
8117c478bd9Sstevel@tonic-gate 		dtype = scsa1394_sbp2_get_lun_type(&sp->s_lun[i]);
8127c478bd9Sstevel@tonic-gate 		scsa1394_dtype2name(dtype, &node_name, &driver_name);
8137c478bd9Sstevel@tonic-gate 
8147c478bd9Sstevel@tonic-gate 		ndi_devi_alloc_sleep(sp->s_dip, node_name,
815fa9e4066Sahrens 		    (pnode_t)DEVI_SID_NODEID, &cdip);
8167c478bd9Sstevel@tonic-gate 
8174c06356bSdh 		ret = ndi_prop_update_int(DDI_DEV_T_NONE, cdip,
8184c06356bSdh 		    SCSI_ADDR_PROP_TARGET, 0);
8197c478bd9Sstevel@tonic-gate 		if (ret != DDI_PROP_SUCCESS) {
8207c478bd9Sstevel@tonic-gate 			(void) ndi_devi_free(cdip);
8217c478bd9Sstevel@tonic-gate 			continue;
8227c478bd9Sstevel@tonic-gate 		}
8237c478bd9Sstevel@tonic-gate 
8244c06356bSdh 		ret = ndi_prop_update_int(DDI_DEV_T_NONE, cdip,
8254c06356bSdh 		    SCSI_ADDR_PROP_LUN, i);
8267c478bd9Sstevel@tonic-gate 		if (ret != DDI_PROP_SUCCESS) {
8277c478bd9Sstevel@tonic-gate 			ddi_prop_remove_all(cdip);
8287c478bd9Sstevel@tonic-gate 			(void) ndi_devi_free(cdip);
8297c478bd9Sstevel@tonic-gate 			continue;
8307c478bd9Sstevel@tonic-gate 		}
8317c478bd9Sstevel@tonic-gate 
8320167b58cScg 		/*
8330167b58cScg 		 * Some devices don't support LOG SENSE, so tell
8340167b58cScg 		 * sd driver not to send this command.
8350167b58cScg 		 */
8360167b58cScg 		ret = ndi_prop_update_int(DDI_DEV_T_NONE, cdip,
8370167b58cScg 		    "pm-capable", 1);
8380167b58cScg 		if (ret != DDI_PROP_SUCCESS) {
8390167b58cScg 			ddi_prop_remove_all(cdip);
8400167b58cScg 			(void) ndi_devi_free(cdip);
8410167b58cScg 			continue;
8420167b58cScg 		}
8430167b58cScg 
8440167b58cScg 		ret = ndi_prop_create_boolean(DDI_DEV_T_NONE, cdip,
8450167b58cScg 		    "hotpluggable");
8460167b58cScg 		if (ret != DDI_PROP_SUCCESS) {
8470167b58cScg 			ddi_prop_remove_all(cdip);
8480167b58cScg 			(void) ndi_devi_free(cdip);
8490167b58cScg 			continue;
8500167b58cScg 		}
8510167b58cScg 
8527c478bd9Sstevel@tonic-gate 		if (driver_name) {
8537c478bd9Sstevel@tonic-gate 			compatible[0] = driver_name;
8547c478bd9Sstevel@tonic-gate 			ret = ndi_prop_update_string_array(DDI_DEV_T_NONE, cdip,
8557c478bd9Sstevel@tonic-gate 			    "compatible", (char **)compatible,
8567c478bd9Sstevel@tonic-gate 			    SCSA1394_COMPAT_MAX);
8577c478bd9Sstevel@tonic-gate 			if (ret != DDI_PROP_SUCCESS) {
8587c478bd9Sstevel@tonic-gate 				ddi_prop_remove_all(cdip);
8597c478bd9Sstevel@tonic-gate 				(void) ndi_devi_free(cdip);
8607c478bd9Sstevel@tonic-gate 				continue;
8617c478bd9Sstevel@tonic-gate 			}
8627c478bd9Sstevel@tonic-gate 		}
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate 		/*
8657c478bd9Sstevel@tonic-gate 		 * add property "scsa1394" to distinguish from others' children
8667c478bd9Sstevel@tonic-gate 		 */
8677c478bd9Sstevel@tonic-gate 		ret = ndi_prop_create_boolean(DDI_DEV_T_NONE, cdip, "scsa1394");
8687c478bd9Sstevel@tonic-gate 		if (ret != DDI_PROP_SUCCESS) {
8697c478bd9Sstevel@tonic-gate 			ddi_prop_remove_all(cdip);
8707c478bd9Sstevel@tonic-gate 			(void) ndi_devi_free(cdip);
8717c478bd9Sstevel@tonic-gate 			continue;
8727c478bd9Sstevel@tonic-gate 		}
8737c478bd9Sstevel@tonic-gate 
8747c478bd9Sstevel@tonic-gate 		(void) ddi_initchild(sp->s_dip, cdip);
8757c478bd9Sstevel@tonic-gate 	}
8767c478bd9Sstevel@tonic-gate }
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate /*ARGSUSED*/
8797c478bd9Sstevel@tonic-gate static void
scsa1394_bus_reset(dev_info_t * dip,ddi_eventcookie_t evc,void * arg,void * data)8807c478bd9Sstevel@tonic-gate scsa1394_bus_reset(dev_info_t *dip, ddi_eventcookie_t evc, void *arg,
8817c478bd9Sstevel@tonic-gate     void *data)
8827c478bd9Sstevel@tonic-gate {
8837c478bd9Sstevel@tonic-gate 	scsa1394_state_t	*sp = arg;
8847c478bd9Sstevel@tonic-gate 
8857c478bd9Sstevel@tonic-gate 	if (sp != NULL) {
8867c478bd9Sstevel@tonic-gate 		mutex_enter(&sp->s_mutex);
8877c478bd9Sstevel@tonic-gate 		if (sp->s_dev_state == SCSA1394_DEV_DISCONNECTED) {
8887c478bd9Sstevel@tonic-gate 			mutex_exit(&sp->s_mutex);
8897c478bd9Sstevel@tonic-gate 			return;
8907c478bd9Sstevel@tonic-gate 		}
8917c478bd9Sstevel@tonic-gate 		sp->s_stat.stat_bus_reset_cnt++;
8927c478bd9Sstevel@tonic-gate 		sp->s_dev_state = SCSA1394_DEV_BUS_RESET;
8937c478bd9Sstevel@tonic-gate 		sp->s_attachinfo.localinfo = *(t1394_localinfo_t *)data;
8947c478bd9Sstevel@tonic-gate 		mutex_exit(&sp->s_mutex);
8957c478bd9Sstevel@tonic-gate 
8967c478bd9Sstevel@tonic-gate 		scsa1394_sbp2_req(sp, 0, SCSA1394_THREQ_BUS_RESET);
8977c478bd9Sstevel@tonic-gate 	}
8987c478bd9Sstevel@tonic-gate }
8997c478bd9Sstevel@tonic-gate 
9007c478bd9Sstevel@tonic-gate /*ARGSUSED*/
9017c478bd9Sstevel@tonic-gate static void
scsa1394_disconnect(dev_info_t * dip,ddi_eventcookie_t evc,void * arg,void * data)9027c478bd9Sstevel@tonic-gate scsa1394_disconnect(dev_info_t *dip, ddi_eventcookie_t evc, void *arg,
9037c478bd9Sstevel@tonic-gate     void *data)
9047c478bd9Sstevel@tonic-gate {
9057c478bd9Sstevel@tonic-gate 	scsa1394_state_t	*sp = arg;
9067c478bd9Sstevel@tonic-gate 	dev_info_t		*cdip, *cdip_next;
9077c478bd9Sstevel@tonic-gate 
9087c478bd9Sstevel@tonic-gate 	if (sp == NULL) {
9097c478bd9Sstevel@tonic-gate 		return;
9107c478bd9Sstevel@tonic-gate 	}
9117c478bd9Sstevel@tonic-gate 
9127c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->s_mutex);
9137c478bd9Sstevel@tonic-gate 	sp->s_stat.stat_disconnect_cnt++;
9147c478bd9Sstevel@tonic-gate 	sp->s_dev_state = SCSA1394_DEV_DISCONNECTED;
9157c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->s_mutex);
9167c478bd9Sstevel@tonic-gate 
9177c478bd9Sstevel@tonic-gate 	scsa1394_sbp2_disconnect(sp);
9187c478bd9Sstevel@tonic-gate 
919*3fe80ca4SDan Cross 	ndi_devi_enter(dip);
9207c478bd9Sstevel@tonic-gate 	for (cdip = ddi_get_child(dip); cdip != NULL; cdip = cdip_next) {
9217c478bd9Sstevel@tonic-gate 		cdip_next = ddi_get_next_sibling(cdip);
9227c478bd9Sstevel@tonic-gate 
9237c478bd9Sstevel@tonic-gate 		mutex_enter(&DEVI(cdip)->devi_lock);
9247c478bd9Sstevel@tonic-gate 		DEVI_SET_DEVICE_REMOVED(cdip);
9257c478bd9Sstevel@tonic-gate 		mutex_exit(&DEVI(cdip)->devi_lock);
9267c478bd9Sstevel@tonic-gate 	}
927*3fe80ca4SDan Cross 	ndi_devi_exit(dip);
9287c478bd9Sstevel@tonic-gate }
9297c478bd9Sstevel@tonic-gate 
9307c478bd9Sstevel@tonic-gate /*ARGSUSED*/
9317c478bd9Sstevel@tonic-gate static void
scsa1394_reconnect(dev_info_t * dip,ddi_eventcookie_t evc,void * arg,void * data)9327c478bd9Sstevel@tonic-gate scsa1394_reconnect(dev_info_t *dip, ddi_eventcookie_t evc, void *arg,
9337c478bd9Sstevel@tonic-gate     void *data)
9347c478bd9Sstevel@tonic-gate {
9357c478bd9Sstevel@tonic-gate 	scsa1394_state_t	*sp = arg;
9367c478bd9Sstevel@tonic-gate 	dev_info_t		*cdip, *cdip_next;
9377c478bd9Sstevel@tonic-gate 
9387c478bd9Sstevel@tonic-gate 	if (sp == NULL) {
9397c478bd9Sstevel@tonic-gate 		return;
9407c478bd9Sstevel@tonic-gate 	}
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->s_mutex);
9437c478bd9Sstevel@tonic-gate 	sp->s_stat.stat_reconnect_cnt++;
9447c478bd9Sstevel@tonic-gate 	sp->s_attachinfo.localinfo = *(t1394_localinfo_t *)data;
9457c478bd9Sstevel@tonic-gate 	sp->s_disconnect_warned = B_FALSE;
9467c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->s_mutex);
9477c478bd9Sstevel@tonic-gate 
948*3fe80ca4SDan Cross 	ndi_devi_enter(dip);
9497c478bd9Sstevel@tonic-gate 	for (cdip = ddi_get_child(dip); cdip != NULL; cdip = cdip_next) {
9507c478bd9Sstevel@tonic-gate 		cdip_next = ddi_get_next_sibling(cdip);
9517c478bd9Sstevel@tonic-gate 
9527c478bd9Sstevel@tonic-gate 		mutex_enter(&DEVI(cdip)->devi_lock);
9537c478bd9Sstevel@tonic-gate 		DEVI_SET_DEVICE_REINSERTED(cdip);
9547c478bd9Sstevel@tonic-gate 		mutex_exit(&DEVI(cdip)->devi_lock);
9557c478bd9Sstevel@tonic-gate 	}
956*3fe80ca4SDan Cross 	ndi_devi_exit(dip);
9577c478bd9Sstevel@tonic-gate 
9587c478bd9Sstevel@tonic-gate 	scsa1394_sbp2_req(sp, 0, SCSA1394_THREQ_RECONNECT);
9597c478bd9Sstevel@tonic-gate }
9607c478bd9Sstevel@tonic-gate 
9617c478bd9Sstevel@tonic-gate /*
9627c478bd9Sstevel@tonic-gate  *
9637c478bd9Sstevel@tonic-gate  * --- SCSA entry points
9647c478bd9Sstevel@tonic-gate  *
9657c478bd9Sstevel@tonic-gate  */
9667c478bd9Sstevel@tonic-gate /*ARGSUSED*/
9677c478bd9Sstevel@tonic-gate static int
scsa1394_scsi_tgt_init(dev_info_t * dip,dev_info_t * cdip,scsi_hba_tran_t * tran,struct scsi_device * sd)9687c478bd9Sstevel@tonic-gate scsa1394_scsi_tgt_init(dev_info_t *dip, dev_info_t *cdip, scsi_hba_tran_t *tran,
9697c478bd9Sstevel@tonic-gate     struct scsi_device *sd)
9707c478bd9Sstevel@tonic-gate {
9717c478bd9Sstevel@tonic-gate 	scsa1394_state_t *sp = (scsa1394_state_t *)tran->tran_hba_private;
9727c478bd9Sstevel@tonic-gate 	int		lun;
9737c478bd9Sstevel@tonic-gate 	int		plen = sizeof (int);
9747c478bd9Sstevel@tonic-gate 	int		ret = DDI_FAILURE;
9757c478bd9Sstevel@tonic-gate 
9767c478bd9Sstevel@tonic-gate 	if (ddi_prop_op(DDI_DEV_T_ANY, cdip, PROP_LEN_AND_VAL_BUF,
9774c06356bSdh 	    DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, SCSI_ADDR_PROP_LUN,
9784c06356bSdh 	    (caddr_t)&lun, &plen) != DDI_PROP_SUCCESS) {
9797c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
9807c478bd9Sstevel@tonic-gate 	}
9817c478bd9Sstevel@tonic-gate 
9827c478bd9Sstevel@tonic-gate 	if (!scsa1394_is_my_child(cdip)) {
9837c478bd9Sstevel@tonic-gate 		/*
9847c478bd9Sstevel@tonic-gate 		 * add property "scsa1394" to distinguish from others' children
9857c478bd9Sstevel@tonic-gate 		 */
9867c478bd9Sstevel@tonic-gate 		ret = ndi_prop_create_boolean(DDI_DEV_T_NONE, cdip, "scsa1394");
9877c478bd9Sstevel@tonic-gate 		if (ret != DDI_PROP_SUCCESS) {
9887c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
9897c478bd9Sstevel@tonic-gate 		}
9907c478bd9Sstevel@tonic-gate 
991f2b7ce3eSartem 		if (scsa1394_dev_is_online(sp)) {
992f2b7ce3eSartem 			return (scsa1394_sbp2_login(sp, lun));
993f2b7ce3eSartem 		} else {
994f2b7ce3eSartem 			return (DDI_FAILURE);
995f2b7ce3eSartem 		}
9967c478bd9Sstevel@tonic-gate 	}
9977c478bd9Sstevel@tonic-gate 
998f2b7ce3eSartem 	if ((lun >= sp->s_nluns) || (sp->s_lun[lun].l_cdip != NULL) ||
999f2b7ce3eSartem 	    !scsa1394_dev_is_online(sp)) {
10007c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
10017c478bd9Sstevel@tonic-gate 	}
10027c478bd9Sstevel@tonic-gate 
10037c478bd9Sstevel@tonic-gate 	if ((ret = scsa1394_sbp2_login(sp, lun)) == DDI_SUCCESS) {
10047c478bd9Sstevel@tonic-gate 		sp->s_lun[lun].l_cdip = cdip;
10057c478bd9Sstevel@tonic-gate 	}
10067c478bd9Sstevel@tonic-gate 	return (ret);
10077c478bd9Sstevel@tonic-gate }
10087c478bd9Sstevel@tonic-gate 
10097c478bd9Sstevel@tonic-gate /*ARGSUSED*/
10107c478bd9Sstevel@tonic-gate static void
scsa1394_scsi_tgt_free(dev_info_t * dip,dev_info_t * cdip,scsi_hba_tran_t * tran,struct scsi_device * sd)10117c478bd9Sstevel@tonic-gate scsa1394_scsi_tgt_free(dev_info_t *dip, dev_info_t *cdip, scsi_hba_tran_t *tran,
10127c478bd9Sstevel@tonic-gate     struct scsi_device *sd)
10137c478bd9Sstevel@tonic-gate {
10147c478bd9Sstevel@tonic-gate 	scsa1394_state_t *sp = (scsa1394_state_t *)tran->tran_hba_private;
10157c478bd9Sstevel@tonic-gate 	int		lun;
10167c478bd9Sstevel@tonic-gate 	int		plen = sizeof (int);
10177c478bd9Sstevel@tonic-gate 
10187c478bd9Sstevel@tonic-gate 	if (!scsa1394_is_my_child(cdip)) {
10197c478bd9Sstevel@tonic-gate 		return;
10207c478bd9Sstevel@tonic-gate 	}
10217c478bd9Sstevel@tonic-gate 
10227c478bd9Sstevel@tonic-gate 	if (ddi_prop_op(DDI_DEV_T_ANY, cdip, PROP_LEN_AND_VAL_BUF,
10234c06356bSdh 	    DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, SCSI_ADDR_PROP_LUN,
10244c06356bSdh 	    (caddr_t)&lun, &plen) != DDI_PROP_SUCCESS) {
10257c478bd9Sstevel@tonic-gate 		return;
10267c478bd9Sstevel@tonic-gate 	}
10277c478bd9Sstevel@tonic-gate 
10287c478bd9Sstevel@tonic-gate 	if ((lun < sp->s_nluns) && (sp->s_lun[lun].l_cdip == cdip)) {
10297c478bd9Sstevel@tonic-gate 		if (scsa1394_dev_is_online(sp)) {
10307c478bd9Sstevel@tonic-gate 			scsa1394_sbp2_logout(sp, lun, B_TRUE);
10317c478bd9Sstevel@tonic-gate 		}
10327c478bd9Sstevel@tonic-gate 		sp->s_lun[lun].l_cdip = NULL;
10337c478bd9Sstevel@tonic-gate 	}
10347c478bd9Sstevel@tonic-gate }
10357c478bd9Sstevel@tonic-gate 
10367c478bd9Sstevel@tonic-gate static int
scsa1394_scsi_tgt_probe(struct scsi_device * sd,int (* waitfunc)())10377c478bd9Sstevel@tonic-gate scsa1394_scsi_tgt_probe(struct scsi_device *sd, int (*waitfunc)())
10387c478bd9Sstevel@tonic-gate {
10397c478bd9Sstevel@tonic-gate 	dev_info_t	*dip = ddi_get_parent(sd->sd_dev);
10407c478bd9Sstevel@tonic-gate 	scsi_hba_tran_t	*tran = (scsi_hba_tran_t *)ddi_get_driver_private(dip);
10417c478bd9Sstevel@tonic-gate 	scsa1394_state_t *sp = (scsa1394_state_t *)tran->tran_hba_private;
10427c478bd9Sstevel@tonic-gate 	scsa1394_lun_t	*lp;
10437c478bd9Sstevel@tonic-gate 
10447c478bd9Sstevel@tonic-gate 	if (!scsa1394_dev_is_online(sp)) {
10457c478bd9Sstevel@tonic-gate 		return (SCSIPROBE_FAILURE);
10467c478bd9Sstevel@tonic-gate 	}
10477c478bd9Sstevel@tonic-gate 	lp = &sp->s_lun[sd->sd_address.a_lun];
10487c478bd9Sstevel@tonic-gate 
10497c478bd9Sstevel@tonic-gate 	if (scsa1394_probe_g0_nodata(sd, waitfunc,
10507c478bd9Sstevel@tonic-gate 	    SCMD_TEST_UNIT_READY, 0, 0) != SCSIPROBE_EXISTS) {
10517c478bd9Sstevel@tonic-gate 		lp->l_nosup_tur = B_TRUE;
10527c478bd9Sstevel@tonic-gate 		(void) scsa1394_sbp2_reset(lp, RESET_LUN, NULL);
10537c478bd9Sstevel@tonic-gate 	}
10547c478bd9Sstevel@tonic-gate 	if (scsa1394_probe_g0_nodata(sd, waitfunc,
10557c478bd9Sstevel@tonic-gate 	    SCMD_START_STOP, 0, 1) != SCSIPROBE_EXISTS) {
10567c478bd9Sstevel@tonic-gate 		lp->l_nosup_start_stop = B_TRUE;
10577c478bd9Sstevel@tonic-gate 	}
10587c478bd9Sstevel@tonic-gate 
10597c478bd9Sstevel@tonic-gate 	/* standard probe issues INQUIRY, which some devices may not support */
10607c478bd9Sstevel@tonic-gate 	if (scsi_hba_probe(sd, waitfunc) != SCSIPROBE_EXISTS) {
10617c478bd9Sstevel@tonic-gate 		lp->l_nosup_inquiry = B_TRUE;
10627c478bd9Sstevel@tonic-gate 		scsa1394_sbp2_fake_inquiry(sp, &lp->l_fake_inq);
10637c478bd9Sstevel@tonic-gate 		bcopy(&lp->l_fake_inq, sd->sd_inq, SUN_INQSIZE);
10647c478bd9Sstevel@tonic-gate #ifndef __lock_lint
10657c478bd9Sstevel@tonic-gate 		lp->l_rmb_orig = 1;
10667c478bd9Sstevel@tonic-gate #endif
10677c478bd9Sstevel@tonic-gate 	}
10687c478bd9Sstevel@tonic-gate 
10690167b58cScg 	if (scsa1394_wrka_fake_rmb) {
10707c478bd9Sstevel@tonic-gate 		sd->sd_inq->inq_rmb = 1;
10717c478bd9Sstevel@tonic-gate 	}
10727c478bd9Sstevel@tonic-gate 
10737c478bd9Sstevel@tonic-gate 	return (SCSIPROBE_EXISTS);
10747c478bd9Sstevel@tonic-gate }
10757c478bd9Sstevel@tonic-gate 
10767c478bd9Sstevel@tonic-gate static int
scsa1394_probe_g0_nodata(struct scsi_device * sd,int (* waitfunc)(),uchar_t cmd,uint_t addr,uint_t cnt)10777c478bd9Sstevel@tonic-gate scsa1394_probe_g0_nodata(struct scsi_device *sd, int (*waitfunc)(),
10787c478bd9Sstevel@tonic-gate     uchar_t cmd, uint_t addr, uint_t cnt)
10797c478bd9Sstevel@tonic-gate {
10807c478bd9Sstevel@tonic-gate 	struct scsi_pkt	*pkt;
10817c478bd9Sstevel@tonic-gate 	int		ret = SCSIPROBE_EXISTS;
10827c478bd9Sstevel@tonic-gate 
10837c478bd9Sstevel@tonic-gate 	pkt = scsi_init_pkt(&sd->sd_address, NULL, NULL, CDB_GROUP0,
10847c478bd9Sstevel@tonic-gate 	    sizeof (struct scsi_arq_status), 0, PKT_CONSISTENT, waitfunc, NULL);
10857c478bd9Sstevel@tonic-gate 
10867c478bd9Sstevel@tonic-gate 	if (pkt == NULL) {
10877c478bd9Sstevel@tonic-gate 		return (SCSIPROBE_NOMEM);
10887c478bd9Sstevel@tonic-gate 	}
10897c478bd9Sstevel@tonic-gate 
10907c478bd9Sstevel@tonic-gate 	(void) scsi_setup_cdb((union scsi_cdb *)pkt->pkt_cdbp, cmd, addr, cnt,
10917c478bd9Sstevel@tonic-gate 	    0);
10927c478bd9Sstevel@tonic-gate 	((union scsi_cdb *)(pkt)->pkt_cdbp)->scc_lun = sd->sd_address.a_lun;
10937c478bd9Sstevel@tonic-gate 	pkt->pkt_flags = FLAG_NOINTR;
10947c478bd9Sstevel@tonic-gate 
10957c478bd9Sstevel@tonic-gate 	if (scsa1394_probe_tran(pkt) < 0) {
10967c478bd9Sstevel@tonic-gate 		if (pkt->pkt_reason == CMD_INCOMPLETE) {
10977c478bd9Sstevel@tonic-gate 			ret = SCSIPROBE_NORESP;
10988c067cfdSAlan Perry 		} else if ((pkt->pkt_reason == CMD_TRAN_ERR) &&
10998c067cfdSAlan Perry 		    ((*(pkt->pkt_scbp) & STATUS_MASK) == STATUS_CHECK) &&
11008c067cfdSAlan Perry 		    (pkt->pkt_state & STATE_ARQ_DONE)) {
11018c067cfdSAlan Perry 			ret = SCSIPROBE_EXISTS;
11027c478bd9Sstevel@tonic-gate 		} else {
11037c478bd9Sstevel@tonic-gate 			ret = SCSIPROBE_FAILURE;
11047c478bd9Sstevel@tonic-gate 		}
11057c478bd9Sstevel@tonic-gate 	}
11067c478bd9Sstevel@tonic-gate 
11077c478bd9Sstevel@tonic-gate 	scsi_destroy_pkt(pkt);
11087c478bd9Sstevel@tonic-gate 
11097c478bd9Sstevel@tonic-gate 	return (ret);
11107c478bd9Sstevel@tonic-gate }
11117c478bd9Sstevel@tonic-gate 
11127c478bd9Sstevel@tonic-gate static int
scsa1394_probe_tran(struct scsi_pkt * pkt)11137c478bd9Sstevel@tonic-gate scsa1394_probe_tran(struct scsi_pkt *pkt)
11147c478bd9Sstevel@tonic-gate {
11157c478bd9Sstevel@tonic-gate 	pkt->pkt_time = SCSA1394_PROBE_TIMEOUT;
11167c478bd9Sstevel@tonic-gate 
11177c478bd9Sstevel@tonic-gate 	if (scsi_transport(pkt) != TRAN_ACCEPT) {
11187c478bd9Sstevel@tonic-gate 		return (-1);
11197c478bd9Sstevel@tonic-gate 	} else if ((pkt->pkt_reason == CMD_INCOMPLETE) &&
11207c478bd9Sstevel@tonic-gate 	    (pkt->pkt_state == 0)) {
11217c478bd9Sstevel@tonic-gate 		return (-1);
11227c478bd9Sstevel@tonic-gate 	} else if (pkt->pkt_reason != CMD_CMPLT) {
11237c478bd9Sstevel@tonic-gate 		return (-1);
11247c478bd9Sstevel@tonic-gate 	} else if (((*pkt->pkt_scbp) & STATUS_MASK) == STATUS_BUSY) {
11257c478bd9Sstevel@tonic-gate 		return (0);
11267c478bd9Sstevel@tonic-gate 	}
11277c478bd9Sstevel@tonic-gate 	return (0);
11287c478bd9Sstevel@tonic-gate }
11297c478bd9Sstevel@tonic-gate 
11307c478bd9Sstevel@tonic-gate /*ARGSUSED*/
11317c478bd9Sstevel@tonic-gate static int
scsa1394_scsi_abort(struct scsi_address * ap,struct scsi_pkt * pkt)11327c478bd9Sstevel@tonic-gate scsa1394_scsi_abort(struct scsi_address *ap, struct scsi_pkt *pkt)
11337c478bd9Sstevel@tonic-gate {
11347c478bd9Sstevel@tonic-gate 	return (0);
11357c478bd9Sstevel@tonic-gate }
11367c478bd9Sstevel@tonic-gate 
11377c478bd9Sstevel@tonic-gate static int
scsa1394_scsi_reset(struct scsi_address * ap,int level)11387c478bd9Sstevel@tonic-gate scsa1394_scsi_reset(struct scsi_address *ap, int level)
11397c478bd9Sstevel@tonic-gate {
11407c478bd9Sstevel@tonic-gate 	scsa1394_state_t *sp = ADDR2STATE(ap);
11417c478bd9Sstevel@tonic-gate 	scsa1394_lun_t	*lp;
11427c478bd9Sstevel@tonic-gate 	int		ret;
11437c478bd9Sstevel@tonic-gate 
11447c478bd9Sstevel@tonic-gate 	switch (level) {
11457c478bd9Sstevel@tonic-gate 	case RESET_ALL:
11467c478bd9Sstevel@tonic-gate 	case RESET_TARGET:
11477c478bd9Sstevel@tonic-gate 		lp = &sp->s_lun[0];
11487c478bd9Sstevel@tonic-gate 		break;
11497c478bd9Sstevel@tonic-gate 	case RESET_LUN:
11507c478bd9Sstevel@tonic-gate 		lp = &sp->s_lun[ap->a_lun];
11517c478bd9Sstevel@tonic-gate 		break;
11527c478bd9Sstevel@tonic-gate 	default:
11537c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
11547c478bd9Sstevel@tonic-gate 	}
11557c478bd9Sstevel@tonic-gate 
11567c478bd9Sstevel@tonic-gate 	ret = scsa1394_sbp2_reset(lp, level, NULL);
11577c478bd9Sstevel@tonic-gate 
11587c478bd9Sstevel@tonic-gate 	return ((ret == SBP2_SUCCESS) ? 1 : 0);
11597c478bd9Sstevel@tonic-gate }
11607c478bd9Sstevel@tonic-gate 
11617c478bd9Sstevel@tonic-gate /*ARGSUSED*/
11627c478bd9Sstevel@tonic-gate static int
scsa1394_scsi_getcap(struct scsi_address * ap,char * cap,int whom)11637c478bd9Sstevel@tonic-gate scsa1394_scsi_getcap(struct scsi_address *ap, char *cap, int whom)
11647c478bd9Sstevel@tonic-gate {
11657c478bd9Sstevel@tonic-gate 	scsa1394_state_t *sp = ADDR2STATE(ap);
11667c478bd9Sstevel@tonic-gate 	size_t		dev_bsize_cap;
11677c478bd9Sstevel@tonic-gate 	int		ret = -1;
11687c478bd9Sstevel@tonic-gate 
11697c478bd9Sstevel@tonic-gate 	if (!scsa1394_dev_is_online(sp)) {
11707c478bd9Sstevel@tonic-gate 		return (-1);
11717c478bd9Sstevel@tonic-gate 	}
11727c478bd9Sstevel@tonic-gate 
11737c478bd9Sstevel@tonic-gate 	if (cap == NULL) {
11747c478bd9Sstevel@tonic-gate 		return (-1);
11757c478bd9Sstevel@tonic-gate 	}
11767c478bd9Sstevel@tonic-gate 
11777c478bd9Sstevel@tonic-gate 	switch (scsi_hba_lookup_capstr(cap)) {
11787c478bd9Sstevel@tonic-gate 	case SCSI_CAP_DMA_MAX:
11797c478bd9Sstevel@tonic-gate 		ret = sp->s_attachinfo.dma_attr.dma_attr_maxxfer;
11807c478bd9Sstevel@tonic-gate 		break;
11817c478bd9Sstevel@tonic-gate 	case SCSI_CAP_SCSI_VERSION:
11827c478bd9Sstevel@tonic-gate 		ret = SCSI_VERSION_2;
11837c478bd9Sstevel@tonic-gate 		break;
11847c478bd9Sstevel@tonic-gate 	case SCSI_CAP_ARQ:
11857c478bd9Sstevel@tonic-gate 		ret = 1;
11867c478bd9Sstevel@tonic-gate 		break;
11877c478bd9Sstevel@tonic-gate 	case SCSI_CAP_UNTAGGED_QING:
11887c478bd9Sstevel@tonic-gate 		ret = 1;
11897c478bd9Sstevel@tonic-gate 		break;
11907c478bd9Sstevel@tonic-gate 	case SCSI_CAP_GEOMETRY:
11917c478bd9Sstevel@tonic-gate 		dev_bsize_cap = sp->s_totalsec;
11927c478bd9Sstevel@tonic-gate 
11937c478bd9Sstevel@tonic-gate 		if (sp->s_secsz > DEV_BSIZE) {
11947c478bd9Sstevel@tonic-gate 			dev_bsize_cap *= sp->s_secsz / DEV_BSIZE;
11957c478bd9Sstevel@tonic-gate 		} else if (sp->s_secsz < DEV_BSIZE) {
11967c478bd9Sstevel@tonic-gate 			dev_bsize_cap /= DEV_BSIZE / sp->s_secsz;
11977c478bd9Sstevel@tonic-gate 		}
11987c478bd9Sstevel@tonic-gate 
11997c478bd9Sstevel@tonic-gate 		if (dev_bsize_cap < 65536 * 2 * 18) {		/* < ~1GB */
12007c478bd9Sstevel@tonic-gate 			/* unlabeled floppy, 18k per cylinder */
12017c478bd9Sstevel@tonic-gate 			ret = ((2 << 16) | 18);
12027c478bd9Sstevel@tonic-gate 		} else if (dev_bsize_cap < 65536 * 64 * 32) {	/* < 64GB */
12037c478bd9Sstevel@tonic-gate 			/* 1024k per cylinder */
12047c478bd9Sstevel@tonic-gate 			ret = ((64 << 16) | 32);
12057c478bd9Sstevel@tonic-gate 		} else if (dev_bsize_cap < 65536 * 255 * 63) {	/* < ~500GB */
12067c478bd9Sstevel@tonic-gate 			/* ~8m per cylinder */
12077c478bd9Sstevel@tonic-gate 			ret = ((255 << 16) | 63);
12087c478bd9Sstevel@tonic-gate 		} else {					/* .. 8TB */
12097c478bd9Sstevel@tonic-gate 			/* 64m per cylinder */
12107c478bd9Sstevel@tonic-gate 			ret = ((512 << 16) | 256);
12117c478bd9Sstevel@tonic-gate 		}
12127c478bd9Sstevel@tonic-gate 		break;
12137c478bd9Sstevel@tonic-gate 	default:
12147c478bd9Sstevel@tonic-gate 		break;
12157c478bd9Sstevel@tonic-gate 	}
12167c478bd9Sstevel@tonic-gate 
12177c478bd9Sstevel@tonic-gate 	return (ret);
12187c478bd9Sstevel@tonic-gate }
12197c478bd9Sstevel@tonic-gate 
12207c478bd9Sstevel@tonic-gate /*ARGSUSED*/
12217c478bd9Sstevel@tonic-gate static int
scsa1394_scsi_setcap(struct scsi_address * ap,char * cap,int value,int whom)12227c478bd9Sstevel@tonic-gate scsa1394_scsi_setcap(struct scsi_address *ap, char *cap, int value, int whom)
12237c478bd9Sstevel@tonic-gate {
12247c478bd9Sstevel@tonic-gate 	scsa1394_state_t *sp = ADDR2STATE(ap);
12257c478bd9Sstevel@tonic-gate 	int		ret = -1;
12267c478bd9Sstevel@tonic-gate 
12277c478bd9Sstevel@tonic-gate 	if (!scsa1394_dev_is_online(sp)) {
12287c478bd9Sstevel@tonic-gate 		return (-1);
12297c478bd9Sstevel@tonic-gate 	}
12307c478bd9Sstevel@tonic-gate 
12317c478bd9Sstevel@tonic-gate 	switch (scsi_hba_lookup_capstr(cap)) {
12327c478bd9Sstevel@tonic-gate 	case SCSI_CAP_ARQ:
12337c478bd9Sstevel@tonic-gate 		ret = 1;
12347c478bd9Sstevel@tonic-gate 		break;
12357c478bd9Sstevel@tonic-gate 	case SCSI_CAP_DMA_MAX:
12367c478bd9Sstevel@tonic-gate 	case SCSI_CAP_SCSI_VERSION:
12377c478bd9Sstevel@tonic-gate 	case SCSI_CAP_UNTAGGED_QING:
12387c478bd9Sstevel@tonic-gate 		/* supported but not settable */
12397c478bd9Sstevel@tonic-gate 		ret = 0;
12407c478bd9Sstevel@tonic-gate 		break;
12417c478bd9Sstevel@tonic-gate 	case SCSI_CAP_SECTOR_SIZE:
12427c478bd9Sstevel@tonic-gate 		if (value) {
12437c478bd9Sstevel@tonic-gate 			sp->s_secsz = value;
12447c478bd9Sstevel@tonic-gate 		}
12457c478bd9Sstevel@tonic-gate 		break;
12467c478bd9Sstevel@tonic-gate 	case SCSI_CAP_TOTAL_SECTORS:
12477c478bd9Sstevel@tonic-gate 		if (value) {
12487c478bd9Sstevel@tonic-gate 			sp->s_totalsec = value;
12497c478bd9Sstevel@tonic-gate 		}
12507c478bd9Sstevel@tonic-gate 		break;
12517c478bd9Sstevel@tonic-gate 	default:
12527c478bd9Sstevel@tonic-gate 		break;
12537c478bd9Sstevel@tonic-gate 	}
12547c478bd9Sstevel@tonic-gate 
12557c478bd9Sstevel@tonic-gate 	return (ret);
12567c478bd9Sstevel@tonic-gate }
12577c478bd9Sstevel@tonic-gate 
12587c478bd9Sstevel@tonic-gate /*ARGSUSED*/
12597c478bd9Sstevel@tonic-gate static void
scsa1394_scsi_sync_pkt(struct scsi_address * ap,struct scsi_pkt * pkt)12607c478bd9Sstevel@tonic-gate scsa1394_scsi_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
12617c478bd9Sstevel@tonic-gate {
12627c478bd9Sstevel@tonic-gate 	scsa1394_cmd_t	*cmd = PKT2CMD(pkt);
12637c478bd9Sstevel@tonic-gate 
12647c478bd9Sstevel@tonic-gate 	if (cmd->sc_flags & SCSA1394_CMD_DMA_BUF_VALID) {
12657c478bd9Sstevel@tonic-gate 		(void) ddi_dma_sync(cmd->sc_buf_dma_hdl, 0, 0,
12667c478bd9Sstevel@tonic-gate 		    (cmd->sc_flags & SCSA1394_CMD_READ) ?
12677c478bd9Sstevel@tonic-gate 		    DDI_DMA_SYNC_FORCPU : DDI_DMA_SYNC_FORDEV);
12687c478bd9Sstevel@tonic-gate 	}
12697c478bd9Sstevel@tonic-gate }
12707c478bd9Sstevel@tonic-gate 
12717c478bd9Sstevel@tonic-gate /*
12727c478bd9Sstevel@tonic-gate  *
12737c478bd9Sstevel@tonic-gate  * --- pkt resource allocation routines
12747c478bd9Sstevel@tonic-gate  *
12757c478bd9Sstevel@tonic-gate  */
12767c478bd9Sstevel@tonic-gate static struct scsi_pkt *
scsa1394_scsi_init_pkt(struct scsi_address * ap,struct scsi_pkt * pkt,struct buf * bp,int cmdlen,int statuslen,int tgtlen,int flags,int (* callback)(),caddr_t arg)12777c478bd9Sstevel@tonic-gate scsa1394_scsi_init_pkt(struct scsi_address *ap, struct scsi_pkt *pkt,
12787c478bd9Sstevel@tonic-gate     struct buf *bp, int cmdlen, int statuslen, int tgtlen, int flags,
12797c478bd9Sstevel@tonic-gate     int (*callback)(), caddr_t arg)
12807c478bd9Sstevel@tonic-gate {
12817c478bd9Sstevel@tonic-gate 	scsa1394_state_t *sp = ADDR2STATE(ap);
12827c478bd9Sstevel@tonic-gate 	scsa1394_lun_t	*lp;
12837c478bd9Sstevel@tonic-gate 	scsa1394_cmd_t	*cmd;
12847c478bd9Sstevel@tonic-gate 	boolean_t	is_new;	/* new cmd is being allocated */
12857c478bd9Sstevel@tonic-gate 	int		kf = (callback == SLEEP_FUNC) ? KM_SLEEP : KM_NOSLEEP;
12867c478bd9Sstevel@tonic-gate 
12877c478bd9Sstevel@tonic-gate 	if (ap->a_lun >= sp->s_nluns) {
12887c478bd9Sstevel@tonic-gate 		return (NULL);
12897c478bd9Sstevel@tonic-gate 	}
12907c478bd9Sstevel@tonic-gate 	lp = &sp->s_lun[ap->a_lun];
12917c478bd9Sstevel@tonic-gate 
12927c478bd9Sstevel@tonic-gate 	/*
12937c478bd9Sstevel@tonic-gate 	 * allocate cmd space
12947c478bd9Sstevel@tonic-gate 	 */
12957c478bd9Sstevel@tonic-gate 	if (pkt == NULL) {
12967c478bd9Sstevel@tonic-gate 		is_new = B_TRUE;
12977c478bd9Sstevel@tonic-gate 		if ((cmd = kmem_cache_alloc(sp->s_cmd_cache, kf)) == NULL) {
12987c478bd9Sstevel@tonic-gate 			return (NULL);
12997c478bd9Sstevel@tonic-gate 		}
13007c478bd9Sstevel@tonic-gate 
13017c478bd9Sstevel@tonic-gate 		/* initialize cmd */
13027c478bd9Sstevel@tonic-gate 		pkt = &cmd->sc_scsi_pkt;
13037c478bd9Sstevel@tonic-gate 		pkt->pkt_ha_private	= cmd;
13047c478bd9Sstevel@tonic-gate 		pkt->pkt_address	= *ap;
13057c478bd9Sstevel@tonic-gate 		pkt->pkt_private	= cmd->sc_priv;
13067c478bd9Sstevel@tonic-gate 		pkt->pkt_scbp		= (uchar_t *)&cmd->sc_scb;
13077c478bd9Sstevel@tonic-gate 		pkt->pkt_cdbp		= (uchar_t *)&cmd->sc_pkt_cdb;
13087c478bd9Sstevel@tonic-gate 		pkt->pkt_resid		= 0;
13097c478bd9Sstevel@tonic-gate 
13107c478bd9Sstevel@tonic-gate 		cmd->sc_lun		= lp;
13117c478bd9Sstevel@tonic-gate 		cmd->sc_pkt		= pkt;
13127c478bd9Sstevel@tonic-gate 		cmd->sc_cdb_len		= cmdlen;
13137c478bd9Sstevel@tonic-gate 		cmd->sc_scb_len		= statuslen;
13147c478bd9Sstevel@tonic-gate 		cmd->sc_priv_len	= tgtlen;
13157c478bd9Sstevel@tonic-gate 
13167c478bd9Sstevel@tonic-gate 		/* need external space? */
13177c478bd9Sstevel@tonic-gate 		if ((cmdlen > sizeof (cmd->sc_pkt_cdb)) ||
13187c478bd9Sstevel@tonic-gate 		    (statuslen > sizeof (cmd->sc_scb)) ||
13197c478bd9Sstevel@tonic-gate 		    (tgtlen > sizeof (cmd->sc_priv))) {
13207c478bd9Sstevel@tonic-gate 			if (scsa1394_cmd_ext_alloc(sp, cmd, kf) !=
13217c478bd9Sstevel@tonic-gate 			    DDI_SUCCESS) {
13227c478bd9Sstevel@tonic-gate 				kmem_cache_free(sp->s_cmd_cache, cmd);
13237c478bd9Sstevel@tonic-gate 				lp->l_stat.stat_err_pkt_kmem_alloc++;
13247c478bd9Sstevel@tonic-gate 				return (NULL);
13257c478bd9Sstevel@tonic-gate 			}
13267c478bd9Sstevel@tonic-gate 		}
13277c478bd9Sstevel@tonic-gate 
13287c478bd9Sstevel@tonic-gate 		/* allocate DMA resources for CDB */
13297c478bd9Sstevel@tonic-gate 		if (scsa1394_cmd_cdb_dma_alloc(sp, cmd, flags, callback, arg) !=
13307c478bd9Sstevel@tonic-gate 		    DDI_SUCCESS) {
13317c478bd9Sstevel@tonic-gate 			scsa1394_scsi_destroy_pkt(ap, pkt);
13327c478bd9Sstevel@tonic-gate 			return (NULL);
13337c478bd9Sstevel@tonic-gate 		}
13347c478bd9Sstevel@tonic-gate 	} else {
13357c478bd9Sstevel@tonic-gate 		is_new = B_FALSE;
13367c478bd9Sstevel@tonic-gate 		cmd = PKT2CMD(pkt);
13377c478bd9Sstevel@tonic-gate 	}
13387c478bd9Sstevel@tonic-gate 
13397c478bd9Sstevel@tonic-gate 	cmd->sc_flags &= ~SCSA1394_CMD_RDWR;
13407c478bd9Sstevel@tonic-gate 
13417c478bd9Sstevel@tonic-gate 	/* allocate/move DMA resources for data buffer */
13427c478bd9Sstevel@tonic-gate 	if ((bp != NULL) && (bp->b_bcount > 0)) {
13437c478bd9Sstevel@tonic-gate 		if ((cmd->sc_flags & SCSA1394_CMD_DMA_BUF_VALID) == 0) {
13447c478bd9Sstevel@tonic-gate 			if (scsa1394_cmd_buf_dma_alloc(sp, cmd, flags, callback,
13457c478bd9Sstevel@tonic-gate 			    arg, bp) != DDI_SUCCESS) {
13467c478bd9Sstevel@tonic-gate 				if (is_new) {
13477c478bd9Sstevel@tonic-gate 					scsa1394_scsi_destroy_pkt(ap, pkt);
13487c478bd9Sstevel@tonic-gate 				}
13497c478bd9Sstevel@tonic-gate 				return (NULL);
13507c478bd9Sstevel@tonic-gate 			}
13517c478bd9Sstevel@tonic-gate 		} else {
13527c478bd9Sstevel@tonic-gate 			if (scsa1394_cmd_buf_dma_move(sp, cmd) != DDI_SUCCESS) {
13537c478bd9Sstevel@tonic-gate 				return (NULL);
13547c478bd9Sstevel@tonic-gate 			}
13557c478bd9Sstevel@tonic-gate 		}
13567c478bd9Sstevel@tonic-gate 
13577c478bd9Sstevel@tonic-gate 		ASSERT(cmd->sc_win_len > 0);
13587c478bd9Sstevel@tonic-gate 		pkt->pkt_resid = bp->b_bcount - cmd->sc_win_len;
13597c478bd9Sstevel@tonic-gate 	}
13607c478bd9Sstevel@tonic-gate 
13617c478bd9Sstevel@tonic-gate 	/*
13627c478bd9Sstevel@tonic-gate 	 * kernel virtual address may be required for certain workarounds
13637c478bd9Sstevel@tonic-gate 	 * and in case of B_PHYS or B_PAGEIO, bp_mapin() will get it for us
13647c478bd9Sstevel@tonic-gate 	 */
13657c478bd9Sstevel@tonic-gate 	if ((bp != NULL) && ((bp->b_flags & (B_PAGEIO | B_PHYS)) != 0) &&
13667c478bd9Sstevel@tonic-gate 	    (bp->b_bcount < SCSA1394_MAPIN_SIZE_MAX) &&
13677c478bd9Sstevel@tonic-gate 	    ((cmd->sc_flags & SCSA1394_CMD_DMA_BUF_MAPIN) == 0)) {
13687c478bd9Sstevel@tonic-gate 		bp_mapin(bp);
13697c478bd9Sstevel@tonic-gate 		cmd->sc_flags |= SCSA1394_CMD_DMA_BUF_MAPIN;
13707c478bd9Sstevel@tonic-gate 	}
13717c478bd9Sstevel@tonic-gate 
13727c478bd9Sstevel@tonic-gate 	return (pkt);
13737c478bd9Sstevel@tonic-gate }
13747c478bd9Sstevel@tonic-gate 
13757c478bd9Sstevel@tonic-gate static void
scsa1394_scsi_destroy_pkt(struct scsi_address * ap,struct scsi_pkt * pkt)13767c478bd9Sstevel@tonic-gate scsa1394_scsi_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
13777c478bd9Sstevel@tonic-gate {
13787c478bd9Sstevel@tonic-gate 	scsa1394_state_t *sp = ADDR2STATE(ap);
13797c478bd9Sstevel@tonic-gate 	scsa1394_cmd_t	*cmd = PKT2CMD(pkt);
13807c478bd9Sstevel@tonic-gate 
13817c478bd9Sstevel@tonic-gate 	if (cmd->sc_flags & SCSA1394_CMD_DMA_BUF_VALID) {
13827c478bd9Sstevel@tonic-gate 		scsa1394_cmd_buf_dma_free(sp, cmd);
13837c478bd9Sstevel@tonic-gate 	}
13847c478bd9Sstevel@tonic-gate 	if (cmd->sc_flags & SCSA1394_CMD_DMA_CDB_VALID) {
13857c478bd9Sstevel@tonic-gate 		scsa1394_cmd_cdb_dma_free(sp, cmd);
13867c478bd9Sstevel@tonic-gate 	}
13877c478bd9Sstevel@tonic-gate 	if (cmd->sc_flags & SCSA1394_CMD_DMA_BUF_MAPIN) {
13887c478bd9Sstevel@tonic-gate 		bp_mapout(cmd->sc_bp);
13897c478bd9Sstevel@tonic-gate 		cmd->sc_flags &= ~SCSA1394_CMD_DMA_BUF_MAPIN;
13907c478bd9Sstevel@tonic-gate 	}
13917c478bd9Sstevel@tonic-gate 	if (cmd->sc_flags & SCSA1394_CMD_EXT) {
13927c478bd9Sstevel@tonic-gate 		scsa1394_cmd_ext_free(sp, cmd);
13937c478bd9Sstevel@tonic-gate 	}
13947c478bd9Sstevel@tonic-gate 
13957c478bd9Sstevel@tonic-gate 	kmem_cache_free(sp->s_cmd_cache, cmd);
13967c478bd9Sstevel@tonic-gate }
13977c478bd9Sstevel@tonic-gate 
13987c478bd9Sstevel@tonic-gate static void
scsa1394_scsi_dmafree(struct scsi_address * ap,struct scsi_pkt * pkt)13997c478bd9Sstevel@tonic-gate scsa1394_scsi_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt)
14007c478bd9Sstevel@tonic-gate {
14017c478bd9Sstevel@tonic-gate 	scsa1394_state_t *sp = ADDR2STATE(ap);
14027c478bd9Sstevel@tonic-gate 	scsa1394_cmd_t	*cmd = PKT2CMD(pkt);
14037c478bd9Sstevel@tonic-gate 
14047c478bd9Sstevel@tonic-gate 	if (cmd->sc_flags & SCSA1394_CMD_DMA_BUF_VALID) {
14057c478bd9Sstevel@tonic-gate 		scsa1394_cmd_buf_dma_free(sp, cmd);
14067c478bd9Sstevel@tonic-gate 	}
14077c478bd9Sstevel@tonic-gate 	if (cmd->sc_flags & SCSA1394_CMD_DMA_BUF_MAPIN) {
14087c478bd9Sstevel@tonic-gate 		bp_mapout(cmd->sc_bp);
14097c478bd9Sstevel@tonic-gate 		cmd->sc_flags &= ~SCSA1394_CMD_DMA_BUF_MAPIN;
14107c478bd9Sstevel@tonic-gate 	}
14117c478bd9Sstevel@tonic-gate }
14127c478bd9Sstevel@tonic-gate 
14137c478bd9Sstevel@tonic-gate /*ARGSUSED*/
14147c478bd9Sstevel@tonic-gate static int
scsa1394_cmd_cache_constructor(void * buf,void * cdrarg,int kf)14157c478bd9Sstevel@tonic-gate scsa1394_cmd_cache_constructor(void *buf, void *cdrarg, int kf)
14167c478bd9Sstevel@tonic-gate {
14177c478bd9Sstevel@tonic-gate 	scsa1394_cmd_t	*cmd = buf;
14187c478bd9Sstevel@tonic-gate 
1419602ca9eaScth 	bzero(buf, SCSA1394_CMD_SIZE);
14207c478bd9Sstevel@tonic-gate 	cmd->sc_task.ts_drv_priv = cmd;
14217c478bd9Sstevel@tonic-gate 
14227c478bd9Sstevel@tonic-gate 	return (0);
14237c478bd9Sstevel@tonic-gate }
14247c478bd9Sstevel@tonic-gate 
14257c478bd9Sstevel@tonic-gate /*ARGSUSED*/
14267c478bd9Sstevel@tonic-gate static void
scsa1394_cmd_cache_destructor(void * buf,void * cdrarg)14277c478bd9Sstevel@tonic-gate scsa1394_cmd_cache_destructor(void *buf, void *cdrarg)
14287c478bd9Sstevel@tonic-gate {
14297c478bd9Sstevel@tonic-gate }
14307c478bd9Sstevel@tonic-gate 
14317c478bd9Sstevel@tonic-gate /*
14327c478bd9Sstevel@tonic-gate  * allocate and deallocate external cmd space (ie. not part of scsa1394_cmd_t)
14337c478bd9Sstevel@tonic-gate  * for non-standard length cdb, pkt_private, status areas
14347c478bd9Sstevel@tonic-gate  */
14357c478bd9Sstevel@tonic-gate static int
scsa1394_cmd_ext_alloc(scsa1394_state_t * sp,scsa1394_cmd_t * cmd,int kf)14367c478bd9Sstevel@tonic-gate scsa1394_cmd_ext_alloc(scsa1394_state_t *sp, scsa1394_cmd_t *cmd, int kf)
14377c478bd9Sstevel@tonic-gate {
14387c478bd9Sstevel@tonic-gate 	struct scsi_pkt	*pkt = cmd->sc_pkt;
14397c478bd9Sstevel@tonic-gate 	void		*buf;
14407c478bd9Sstevel@tonic-gate 
14417c478bd9Sstevel@tonic-gate 	if (cmd->sc_cdb_len > sizeof (cmd->sc_pkt_cdb)) {
14427c478bd9Sstevel@tonic-gate 		if ((buf = kmem_zalloc(cmd->sc_cdb_len, kf)) == NULL) {
14437c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
14447c478bd9Sstevel@tonic-gate 		}
14457c478bd9Sstevel@tonic-gate 		pkt->pkt_cdbp = buf;
14467c478bd9Sstevel@tonic-gate 		cmd->sc_flags |= SCSA1394_CMD_CDB_EXT;
14477c478bd9Sstevel@tonic-gate 	}
14487c478bd9Sstevel@tonic-gate 
14497c478bd9Sstevel@tonic-gate 	if (cmd->sc_scb_len > sizeof (cmd->sc_scb)) {
14507c478bd9Sstevel@tonic-gate 		if ((buf = kmem_zalloc(cmd->sc_scb_len, kf)) == NULL) {
14517c478bd9Sstevel@tonic-gate 			scsa1394_cmd_ext_free(sp, cmd);
14527c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
14537c478bd9Sstevel@tonic-gate 		}
14547c478bd9Sstevel@tonic-gate 		pkt->pkt_scbp = buf;
14557c478bd9Sstevel@tonic-gate 		cmd->sc_flags |= SCSA1394_CMD_SCB_EXT;
14567c478bd9Sstevel@tonic-gate 	}
14577c478bd9Sstevel@tonic-gate 
14587c478bd9Sstevel@tonic-gate 	if (cmd->sc_priv_len > sizeof (cmd->sc_priv)) {
14597c478bd9Sstevel@tonic-gate 		if ((buf = kmem_zalloc(cmd->sc_priv_len, kf)) == NULL) {
14607c478bd9Sstevel@tonic-gate 			scsa1394_cmd_ext_free(sp, cmd);
14617c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
14627c478bd9Sstevel@tonic-gate 		}
14637c478bd9Sstevel@tonic-gate 		pkt->pkt_private = buf;
14647c478bd9Sstevel@tonic-gate 		cmd->sc_flags |= SCSA1394_CMD_PRIV_EXT;
14657c478bd9Sstevel@tonic-gate 	}
14667c478bd9Sstevel@tonic-gate 
14677c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
14687c478bd9Sstevel@tonic-gate }
14697c478bd9Sstevel@tonic-gate 
14707c478bd9Sstevel@tonic-gate /*ARGSUSED*/
14717c478bd9Sstevel@tonic-gate static void
scsa1394_cmd_ext_free(scsa1394_state_t * sp,scsa1394_cmd_t * cmd)14727c478bd9Sstevel@tonic-gate scsa1394_cmd_ext_free(scsa1394_state_t *sp, scsa1394_cmd_t *cmd)
14737c478bd9Sstevel@tonic-gate {
14747c478bd9Sstevel@tonic-gate 	struct scsi_pkt	*pkt = cmd->sc_pkt;
14757c478bd9Sstevel@tonic-gate 
14767c478bd9Sstevel@tonic-gate 	if (cmd->sc_flags & SCSA1394_CMD_CDB_EXT) {
14777c478bd9Sstevel@tonic-gate 		kmem_free(pkt->pkt_cdbp, cmd->sc_cdb_len);
14787c478bd9Sstevel@tonic-gate 	}
14797c478bd9Sstevel@tonic-gate 	if (cmd->sc_flags & SCSA1394_CMD_SCB_EXT) {
14807c478bd9Sstevel@tonic-gate 		kmem_free(pkt->pkt_scbp, cmd->sc_scb_len);
14817c478bd9Sstevel@tonic-gate 	}
14827c478bd9Sstevel@tonic-gate 	if (cmd->sc_flags & SCSA1394_CMD_PRIV_EXT) {
14837c478bd9Sstevel@tonic-gate 		kmem_free(pkt->pkt_private, cmd->sc_priv_len);
14847c478bd9Sstevel@tonic-gate 	}
14857c478bd9Sstevel@tonic-gate 	cmd->sc_flags &= ~SCSA1394_CMD_EXT;
14867c478bd9Sstevel@tonic-gate }
14877c478bd9Sstevel@tonic-gate 
14887c478bd9Sstevel@tonic-gate /*ARGSUSED*/
14897c478bd9Sstevel@tonic-gate static int
scsa1394_cmd_cdb_dma_alloc(scsa1394_state_t * sp,scsa1394_cmd_t * cmd,int flags,int (* callback)(),caddr_t arg)14907c478bd9Sstevel@tonic-gate scsa1394_cmd_cdb_dma_alloc(scsa1394_state_t *sp, scsa1394_cmd_t *cmd,
14917c478bd9Sstevel@tonic-gate     int flags, int (*callback)(), caddr_t arg)
14927c478bd9Sstevel@tonic-gate {
14937c478bd9Sstevel@tonic-gate 	if (sbp2_task_orb_alloc(cmd->sc_lun->l_lun, &cmd->sc_task,
14947c478bd9Sstevel@tonic-gate 	    sizeof (scsa1394_cmd_orb_t)) != SBP2_SUCCESS) {
14957c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
14967c478bd9Sstevel@tonic-gate 	}
14977c478bd9Sstevel@tonic-gate 
14987c478bd9Sstevel@tonic-gate 	cmd->sc_flags |= SCSA1394_CMD_DMA_CDB_VALID;
14997c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
15007c478bd9Sstevel@tonic-gate }
15017c478bd9Sstevel@tonic-gate 
15027c478bd9Sstevel@tonic-gate /*ARGSUSED*/
15037c478bd9Sstevel@tonic-gate static void
scsa1394_cmd_cdb_dma_free(scsa1394_state_t * sp,scsa1394_cmd_t * cmd)15047c478bd9Sstevel@tonic-gate scsa1394_cmd_cdb_dma_free(scsa1394_state_t *sp, scsa1394_cmd_t *cmd)
15057c478bd9Sstevel@tonic-gate {
15067c478bd9Sstevel@tonic-gate 	sbp2_task_orb_free(cmd->sc_lun->l_lun, &cmd->sc_task);
15077c478bd9Sstevel@tonic-gate 	cmd->sc_flags &= ~SCSA1394_CMD_DMA_CDB_VALID;
15087c478bd9Sstevel@tonic-gate }
15097c478bd9Sstevel@tonic-gate 
15107c478bd9Sstevel@tonic-gate /*
15117c478bd9Sstevel@tonic-gate  * buffer resources
15127c478bd9Sstevel@tonic-gate  */
15137c478bd9Sstevel@tonic-gate static int
scsa1394_cmd_buf_dma_alloc(scsa1394_state_t * sp,scsa1394_cmd_t * cmd,int flags,int (* callback)(),caddr_t arg,struct buf * bp)15147c478bd9Sstevel@tonic-gate scsa1394_cmd_buf_dma_alloc(scsa1394_state_t *sp, scsa1394_cmd_t *cmd,
15157c478bd9Sstevel@tonic-gate     int flags, int (*callback)(), caddr_t arg, struct buf *bp)
15167c478bd9Sstevel@tonic-gate {
15177c478bd9Sstevel@tonic-gate 	scsa1394_lun_t	*lp = cmd->sc_lun;
15187c478bd9Sstevel@tonic-gate 	int		kf = (callback == SLEEP_FUNC) ? KM_SLEEP : KM_NOSLEEP;
15197c478bd9Sstevel@tonic-gate 	int		dma_flags;
15207c478bd9Sstevel@tonic-gate 	ddi_dma_cookie_t dmac;
15217c478bd9Sstevel@tonic-gate 	uint_t		ccount;
15227c478bd9Sstevel@tonic-gate 	int		error;
15237c478bd9Sstevel@tonic-gate 	int		ret;
15247c478bd9Sstevel@tonic-gate 
15257c478bd9Sstevel@tonic-gate 	cmd->sc_bp = bp;
15267c478bd9Sstevel@tonic-gate 
15277c478bd9Sstevel@tonic-gate 	if ((ddi_dma_alloc_handle(sp->s_dip, &sp->s_buf_dma_attr, callback,
15287c478bd9Sstevel@tonic-gate 	    NULL, &cmd->sc_buf_dma_hdl)) != DDI_SUCCESS) {
15297c478bd9Sstevel@tonic-gate 		bioerror(bp, 0);
15307c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
15317c478bd9Sstevel@tonic-gate 	}
15327c478bd9Sstevel@tonic-gate 
15337c478bd9Sstevel@tonic-gate 	cmd->sc_flags &= ~SCSA1394_CMD_RDWR;
15347c478bd9Sstevel@tonic-gate 	if (bp->b_flags & B_READ) {
15357c478bd9Sstevel@tonic-gate 		dma_flags = DDI_DMA_READ;
15367c478bd9Sstevel@tonic-gate 		cmd->sc_flags |= SCSA1394_CMD_READ;
15377c478bd9Sstevel@tonic-gate 	} else {
15387c478bd9Sstevel@tonic-gate 		dma_flags = DDI_DMA_WRITE;
15397c478bd9Sstevel@tonic-gate 		cmd->sc_flags |= SCSA1394_CMD_WRITE;
15407c478bd9Sstevel@tonic-gate 	}
15417c478bd9Sstevel@tonic-gate 	if (flags & PKT_CONSISTENT) {
15427c478bd9Sstevel@tonic-gate 		dma_flags |= DDI_DMA_CONSISTENT;
15437c478bd9Sstevel@tonic-gate 	}
15447c478bd9Sstevel@tonic-gate 	if (flags & PKT_DMA_PARTIAL) {
15457c478bd9Sstevel@tonic-gate 		dma_flags |= DDI_DMA_PARTIAL;
15467c478bd9Sstevel@tonic-gate 	}
15477c478bd9Sstevel@tonic-gate 
15487c478bd9Sstevel@tonic-gate 	ret = ddi_dma_buf_bind_handle(cmd->sc_buf_dma_hdl, bp, dma_flags,
15497c478bd9Sstevel@tonic-gate 	    callback, arg, &dmac, &ccount);
15507c478bd9Sstevel@tonic-gate 
15517c478bd9Sstevel@tonic-gate 	switch (ret) {
15527c478bd9Sstevel@tonic-gate 	case DDI_DMA_MAPPED:
15537c478bd9Sstevel@tonic-gate 		cmd->sc_nwin = 1;
15547c478bd9Sstevel@tonic-gate 		cmd->sc_curwin = 0;
15557c478bd9Sstevel@tonic-gate 		cmd->sc_win_offset = 0;
15567c478bd9Sstevel@tonic-gate 		cmd->sc_win_len = bp->b_bcount;
15577c478bd9Sstevel@tonic-gate 		break;
15587c478bd9Sstevel@tonic-gate 
15597c478bd9Sstevel@tonic-gate 	case DDI_DMA_PARTIAL_MAP:
15607c478bd9Sstevel@tonic-gate 		/* retrieve number of windows and first window cookie */
15617c478bd9Sstevel@tonic-gate 		cmd->sc_curwin = 0;
15627c478bd9Sstevel@tonic-gate 		if ((ddi_dma_numwin(cmd->sc_buf_dma_hdl, &cmd->sc_nwin) !=
15637c478bd9Sstevel@tonic-gate 		    DDI_SUCCESS) ||
15647c478bd9Sstevel@tonic-gate 		    (ddi_dma_getwin(cmd->sc_buf_dma_hdl, cmd->sc_curwin,
15657c478bd9Sstevel@tonic-gate 		    &cmd->sc_win_offset, &cmd->sc_win_len, &dmac, &ccount) !=
15667c478bd9Sstevel@tonic-gate 		    DDI_SUCCESS)) {
15677c478bd9Sstevel@tonic-gate 			(void) ddi_dma_unbind_handle(cmd->sc_buf_dma_hdl);
15687c478bd9Sstevel@tonic-gate 			ddi_dma_free_handle(&cmd->sc_buf_dma_hdl);
15697c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
15707c478bd9Sstevel@tonic-gate 		}
1571f2b7ce3eSartem 		lp->l_stat.stat_cmd_buf_dma_partial++;
15727c478bd9Sstevel@tonic-gate 		break;
15737c478bd9Sstevel@tonic-gate 
15747c478bd9Sstevel@tonic-gate 	case DDI_DMA_NORESOURCES:
15757c478bd9Sstevel@tonic-gate 		error = 0;
15767c478bd9Sstevel@tonic-gate 		goto map_error;
15777c478bd9Sstevel@tonic-gate 
15787c478bd9Sstevel@tonic-gate 	case DDI_DMA_BADATTR:
15797c478bd9Sstevel@tonic-gate 	case DDI_DMA_NOMAPPING:
15807c478bd9Sstevel@tonic-gate 		error = EFAULT;
15817c478bd9Sstevel@tonic-gate 		goto map_error;
15827c478bd9Sstevel@tonic-gate 
15837c478bd9Sstevel@tonic-gate 	default:
15847c478bd9Sstevel@tonic-gate 		error = EINVAL;
15857c478bd9Sstevel@tonic-gate 
15867c478bd9Sstevel@tonic-gate 	map_error:
15877c478bd9Sstevel@tonic-gate 		bioerror(bp, error);
15887c478bd9Sstevel@tonic-gate 		lp->l_stat.stat_err_cmd_buf_dbind++;
15897c478bd9Sstevel@tonic-gate 		ddi_dma_free_handle(&cmd->sc_buf_dma_hdl);
15907c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
15917c478bd9Sstevel@tonic-gate 	}
15927c478bd9Sstevel@tonic-gate 	cmd->sc_flags |= SCSA1394_CMD_DMA_BUF_BIND_VALID;
15937c478bd9Sstevel@tonic-gate 
15947c478bd9Sstevel@tonic-gate 	/*
15957c478bd9Sstevel@tonic-gate 	 * setup page table if needed
15967c478bd9Sstevel@tonic-gate 	 */
15977c478bd9Sstevel@tonic-gate 	if ((ccount == 1) && (dmac.dmac_size <= SBP2_PT_SEGSIZE_MAX) &&
15987c478bd9Sstevel@tonic-gate 	    (!sp->s_symbios ||
15997c478bd9Sstevel@tonic-gate 	    (dmac.dmac_size <= scsa1394_symbios_page_size))) {
16007c478bd9Sstevel@tonic-gate 		cmd->sc_buf_nsegs = 1;
16017c478bd9Sstevel@tonic-gate 		cmd->sc_buf_seg_mem.ss_len = dmac.dmac_size;
16027c478bd9Sstevel@tonic-gate 		cmd->sc_buf_seg_mem.ss_daddr = dmac.dmac_address;
16037c478bd9Sstevel@tonic-gate 		cmd->sc_buf_seg = &cmd->sc_buf_seg_mem;
16047c478bd9Sstevel@tonic-gate 	} else {
16057c478bd9Sstevel@tonic-gate 		/* break window into segments */
16067c478bd9Sstevel@tonic-gate 		if (scsa1394_cmd_dmac2seg(sp, cmd, &dmac, ccount, kf) !=
16077c478bd9Sstevel@tonic-gate 		    DDI_SUCCESS) {
16087c478bd9Sstevel@tonic-gate 			scsa1394_cmd_buf_dma_free(sp, cmd);
16097c478bd9Sstevel@tonic-gate 			bioerror(bp, 0);
16107c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
16117c478bd9Sstevel@tonic-gate 		}
16127c478bd9Sstevel@tonic-gate 
16137c478bd9Sstevel@tonic-gate 		/* allocate DMA resources for page table */
16147c478bd9Sstevel@tonic-gate 		if (scsa1394_cmd_pt_dma_alloc(sp, cmd, callback, arg,
16157c478bd9Sstevel@tonic-gate 		    cmd->sc_buf_nsegs) != DDI_SUCCESS) {
16167c478bd9Sstevel@tonic-gate 			scsa1394_cmd_buf_dma_free(sp, cmd);
16177c478bd9Sstevel@tonic-gate 			bioerror(bp, 0);
16187c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
16197c478bd9Sstevel@tonic-gate 		}
16207c478bd9Sstevel@tonic-gate 	}
16217c478bd9Sstevel@tonic-gate 
16227c478bd9Sstevel@tonic-gate 	/* allocate 1394 addresses for segments */
16237c478bd9Sstevel@tonic-gate 	if (scsa1394_cmd_buf_addr_alloc(sp, cmd) != DDI_SUCCESS) {
16247c478bd9Sstevel@tonic-gate 		scsa1394_cmd_buf_dma_free(sp, cmd);
16257c478bd9Sstevel@tonic-gate 		bioerror(bp, 0);
16267c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
16277c478bd9Sstevel@tonic-gate 	}
16287c478bd9Sstevel@tonic-gate 
16297c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
16307c478bd9Sstevel@tonic-gate }
16317c478bd9Sstevel@tonic-gate 
16327c478bd9Sstevel@tonic-gate static void
scsa1394_cmd_buf_dma_free(scsa1394_state_t * sp,scsa1394_cmd_t * cmd)16337c478bd9Sstevel@tonic-gate scsa1394_cmd_buf_dma_free(scsa1394_state_t *sp, scsa1394_cmd_t *cmd)
16347c478bd9Sstevel@tonic-gate {
16357c478bd9Sstevel@tonic-gate 	scsa1394_cmd_buf_addr_free(sp, cmd);
16367c478bd9Sstevel@tonic-gate 	if (cmd->sc_flags & SCSA1394_CMD_DMA_BUF_PT_VALID) {
16377c478bd9Sstevel@tonic-gate 		scsa1394_cmd_pt_dma_free(sp, cmd);
16387c478bd9Sstevel@tonic-gate 	}
16397c478bd9Sstevel@tonic-gate 	scsa1394_cmd_seg_free(sp, cmd);
16407c478bd9Sstevel@tonic-gate 	if (cmd->sc_flags & SCSA1394_CMD_DMA_BUF_BIND_VALID) {
16417c478bd9Sstevel@tonic-gate 		(void) ddi_dma_unbind_handle(cmd->sc_buf_dma_hdl);
16427c478bd9Sstevel@tonic-gate 		ddi_dma_free_handle(&cmd->sc_buf_dma_hdl);
16437c478bd9Sstevel@tonic-gate 	}
16447c478bd9Sstevel@tonic-gate 	cmd->sc_flags &= ~(SCSA1394_CMD_DMA_BUF_VALID | SCSA1394_CMD_RDWR);
16457c478bd9Sstevel@tonic-gate }
16467c478bd9Sstevel@tonic-gate 
16477c478bd9Sstevel@tonic-gate /*
16487c478bd9Sstevel@tonic-gate  * Break a set DMA cookies into segments suitable for SBP-2 page table.
16497c478bd9Sstevel@tonic-gate  * This routine can reuse/reallocate segment array from previous calls.
16507c478bd9Sstevel@tonic-gate  */
16517c478bd9Sstevel@tonic-gate static int
scsa1394_cmd_dmac2seg(scsa1394_state_t * sp,scsa1394_cmd_t * cmd,ddi_dma_cookie_t * dmac,uint_t ccount,int kf)16527c478bd9Sstevel@tonic-gate scsa1394_cmd_dmac2seg(scsa1394_state_t *sp, scsa1394_cmd_t *cmd,
16537c478bd9Sstevel@tonic-gate     ddi_dma_cookie_t *dmac, uint_t ccount, int kf)
16547c478bd9Sstevel@tonic-gate {
16557c478bd9Sstevel@tonic-gate 	scsa1394_lun_t	*lp = cmd->sc_lun;
16567c478bd9Sstevel@tonic-gate 	int		i;
16577c478bd9Sstevel@tonic-gate 	int		nsegs;
16587c478bd9Sstevel@tonic-gate 	size_t		segsize_max;
16597c478bd9Sstevel@tonic-gate 	size_t		dmac_resid;
16607c478bd9Sstevel@tonic-gate 	uint32_t	dmac_addr;
16617c478bd9Sstevel@tonic-gate 	scsa1394_cmd_seg_t *seg;
16627c478bd9Sstevel@tonic-gate 
16637c478bd9Sstevel@tonic-gate 	if (!sp->s_symbios) {
16647c478bd9Sstevel@tonic-gate 		/*
16657c478bd9Sstevel@tonic-gate 		 * Number of segments is unknown at this point. Start with
16667c478bd9Sstevel@tonic-gate 		 * a reasonable estimate and grow it later if needed.
16677c478bd9Sstevel@tonic-gate 		 */
16687c478bd9Sstevel@tonic-gate 		nsegs = max(ccount, cmd->sc_win_len / SBP2_PT_SEGSIZE_MAX) * 2;
16697c478bd9Sstevel@tonic-gate 		segsize_max = SBP2_PT_SEGSIZE_MAX;
16707c478bd9Sstevel@tonic-gate 	} else {
1671f2b7ce3eSartem 		/*
1672f2b7ce3eSartem 		 * For Symbios workaround we know exactly the number of segments
1673f2b7ce3eSartem 		 * Additional segment may be needed if buffer is not aligned.
1674f2b7ce3eSartem 		 */
1675f2b7ce3eSartem 		nsegs =
1676f2b7ce3eSartem 		    howmany(cmd->sc_win_len, scsa1394_symbios_page_size) + 1;
16777c478bd9Sstevel@tonic-gate 		segsize_max = scsa1394_symbios_page_size;
16787c478bd9Sstevel@tonic-gate 	}
16797c478bd9Sstevel@tonic-gate 
16807c478bd9Sstevel@tonic-gate 	if (nsegs > cmd->sc_buf_nsegs_alloc) {
16817c478bd9Sstevel@tonic-gate 		if ((cmd->sc_buf_seg = scsa1394_kmem_realloc(cmd->sc_buf_seg,
16827c478bd9Sstevel@tonic-gate 		    cmd->sc_buf_nsegs_alloc, nsegs,
16837c478bd9Sstevel@tonic-gate 		    sizeof (scsa1394_cmd_seg_t), kf)) == NULL) {
16847c478bd9Sstevel@tonic-gate 			cmd->sc_buf_nsegs_alloc = 0;
16857c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
16867c478bd9Sstevel@tonic-gate 		}
16877c478bd9Sstevel@tonic-gate 		cmd->sc_buf_nsegs_alloc = nsegs;
16887c478bd9Sstevel@tonic-gate 	}
16897c478bd9Sstevel@tonic-gate 
16907c478bd9Sstevel@tonic-gate 	/* each cookie maps into one or more segments */
16917c478bd9Sstevel@tonic-gate 	cmd->sc_buf_nsegs = 0;
16927c478bd9Sstevel@tonic-gate 	i = ccount;
16937c478bd9Sstevel@tonic-gate 	for (;;) {
16947c478bd9Sstevel@tonic-gate 		dmac_resid = dmac->dmac_size;
16957c478bd9Sstevel@tonic-gate 		dmac_addr = dmac->dmac_address;
16967c478bd9Sstevel@tonic-gate 		while (dmac_resid > 0) {
16977c478bd9Sstevel@tonic-gate 			/* grow array if needed */
16987c478bd9Sstevel@tonic-gate 			if (cmd->sc_buf_nsegs >= cmd->sc_buf_nsegs_alloc) {
16997c478bd9Sstevel@tonic-gate 				if ((cmd->sc_buf_seg = scsa1394_kmem_realloc(
17007c478bd9Sstevel@tonic-gate 				    cmd->sc_buf_seg,
17017c478bd9Sstevel@tonic-gate 				    cmd->sc_buf_nsegs_alloc,
17027c478bd9Sstevel@tonic-gate 				    cmd->sc_buf_nsegs_alloc + ccount,
17037c478bd9Sstevel@tonic-gate 				    sizeof (scsa1394_cmd_seg_t), kf)) == NULL) {
17047c478bd9Sstevel@tonic-gate 					return (DDI_FAILURE);
17057c478bd9Sstevel@tonic-gate 				}
17067c478bd9Sstevel@tonic-gate 				cmd->sc_buf_nsegs_alloc += ccount;
17077c478bd9Sstevel@tonic-gate 			}
17087c478bd9Sstevel@tonic-gate 
17097c478bd9Sstevel@tonic-gate 			seg = &cmd->sc_buf_seg[cmd->sc_buf_nsegs];
17107c478bd9Sstevel@tonic-gate 			seg->ss_len = min(dmac_resid, segsize_max);
17117c478bd9Sstevel@tonic-gate 			seg->ss_daddr = (uint64_t)dmac_addr;
17127c478bd9Sstevel@tonic-gate 			dmac_addr += seg->ss_len;
17137c478bd9Sstevel@tonic-gate 			dmac_resid -= seg->ss_len;
17147c478bd9Sstevel@tonic-gate 			cmd->sc_buf_nsegs++;
17157c478bd9Sstevel@tonic-gate 		}
17167c478bd9Sstevel@tonic-gate 		ASSERT(dmac_resid == 0);
17177c478bd9Sstevel@tonic-gate 
17187c478bd9Sstevel@tonic-gate 		/* grab next cookie */
17197c478bd9Sstevel@tonic-gate 		if (--i <= 0) {
17207c478bd9Sstevel@tonic-gate 			break;
17217c478bd9Sstevel@tonic-gate 		}
17227c478bd9Sstevel@tonic-gate 		ddi_dma_nextcookie(cmd->sc_buf_dma_hdl, dmac);
17237c478bd9Sstevel@tonic-gate 	}
17247c478bd9Sstevel@tonic-gate 
17257c478bd9Sstevel@tonic-gate 	if (cmd->sc_buf_nsegs > lp->l_stat.stat_cmd_buf_max_nsegs) {
17267c478bd9Sstevel@tonic-gate 		lp->l_stat.stat_cmd_buf_max_nsegs = cmd->sc_buf_nsegs;
17277c478bd9Sstevel@tonic-gate 	}
17287c478bd9Sstevel@tonic-gate 
17297c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
17307c478bd9Sstevel@tonic-gate }
17317c478bd9Sstevel@tonic-gate 
17327c478bd9Sstevel@tonic-gate /*ARGSUSED*/
17337c478bd9Sstevel@tonic-gate static void
scsa1394_cmd_seg_free(scsa1394_state_t * sp,scsa1394_cmd_t * cmd)17347c478bd9Sstevel@tonic-gate scsa1394_cmd_seg_free(scsa1394_state_t *sp, scsa1394_cmd_t *cmd)
17357c478bd9Sstevel@tonic-gate {
17367c478bd9Sstevel@tonic-gate 	if (cmd->sc_buf_nsegs_alloc > 0) {
17377c478bd9Sstevel@tonic-gate 		kmem_free(cmd->sc_buf_seg, cmd->sc_buf_nsegs_alloc *
17387c478bd9Sstevel@tonic-gate 		    sizeof (scsa1394_cmd_seg_t));
17397c478bd9Sstevel@tonic-gate 	}
17407c478bd9Sstevel@tonic-gate 	cmd->sc_buf_seg = NULL;
17417c478bd9Sstevel@tonic-gate 	cmd->sc_buf_nsegs = 0;
17427c478bd9Sstevel@tonic-gate 	cmd->sc_buf_nsegs_alloc = 0;
17437c478bd9Sstevel@tonic-gate }
17447c478bd9Sstevel@tonic-gate 
17457c478bd9Sstevel@tonic-gate static int
scsa1394_cmd_pt_dma_alloc(scsa1394_state_t * sp,scsa1394_cmd_t * cmd,int (* callback)(),caddr_t arg,int cnt)17467c478bd9Sstevel@tonic-gate scsa1394_cmd_pt_dma_alloc(scsa1394_state_t *sp, scsa1394_cmd_t *cmd,
17477c478bd9Sstevel@tonic-gate     int (*callback)(), caddr_t arg, int cnt)
17487c478bd9Sstevel@tonic-gate {
17497c478bd9Sstevel@tonic-gate 	scsa1394_lun_t	*lp = cmd->sc_lun;
17507c478bd9Sstevel@tonic-gate 	size_t		len, rlen;
17517c478bd9Sstevel@tonic-gate 	uint_t		ccount;
17527c478bd9Sstevel@tonic-gate 	t1394_alloc_addr_t aa;
17537c478bd9Sstevel@tonic-gate 	int		result;
17547c478bd9Sstevel@tonic-gate 
17557c478bd9Sstevel@tonic-gate 	/* allocate DMA memory for page table */
17567c478bd9Sstevel@tonic-gate 	if ((ddi_dma_alloc_handle(sp->s_dip, &sp->s_pt_dma_attr,
17577c478bd9Sstevel@tonic-gate 	    callback, NULL, &cmd->sc_pt_dma_hdl)) != DDI_SUCCESS) {
17587c478bd9Sstevel@tonic-gate 		lp->l_stat.stat_err_cmd_pt_dmem_alloc++;
17597c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
17607c478bd9Sstevel@tonic-gate 	}
17617c478bd9Sstevel@tonic-gate 
17627c478bd9Sstevel@tonic-gate 	cmd->sc_pt_ent_alloc = cnt;
17637c478bd9Sstevel@tonic-gate 	len = cmd->sc_pt_ent_alloc * SBP2_PT_ENT_SIZE;
17647c478bd9Sstevel@tonic-gate 	if (ddi_dma_mem_alloc(cmd->sc_pt_dma_hdl, len,
17657c478bd9Sstevel@tonic-gate 	    &sp->s_attachinfo.acc_attr, DDI_DMA_CONSISTENT, callback, arg,
17667c478bd9Sstevel@tonic-gate 	    &cmd->sc_pt_kaddr, &rlen, &cmd->sc_pt_acc_hdl) != DDI_SUCCESS) {
17677c478bd9Sstevel@tonic-gate 		ddi_dma_free_handle(&cmd->sc_pt_dma_hdl);
17687c478bd9Sstevel@tonic-gate 		lp->l_stat.stat_err_cmd_pt_dmem_alloc++;
17697c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
17707c478bd9Sstevel@tonic-gate 	}
17717c478bd9Sstevel@tonic-gate 
17727c478bd9Sstevel@tonic-gate 	if (ddi_dma_addr_bind_handle(cmd->sc_pt_dma_hdl, NULL,
17737c478bd9Sstevel@tonic-gate 	    cmd->sc_pt_kaddr, len, DDI_DMA_READ | DDI_DMA_CONSISTENT,
17747c478bd9Sstevel@tonic-gate 	    callback, arg, &cmd->sc_pt_dmac, &ccount) != DDI_DMA_MAPPED) {
17757c478bd9Sstevel@tonic-gate 		ddi_dma_mem_free(&cmd->sc_pt_acc_hdl);
17767c478bd9Sstevel@tonic-gate 		ddi_dma_free_handle(&cmd->sc_pt_dma_hdl);
17777c478bd9Sstevel@tonic-gate 		lp->l_stat.stat_err_cmd_pt_dmem_alloc++;
17787c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
17797c478bd9Sstevel@tonic-gate 	}
17807c478bd9Sstevel@tonic-gate 	ASSERT(ccount == 1);	/* because dma_attr_sgllen is 1 */
17817c478bd9Sstevel@tonic-gate 
17827c478bd9Sstevel@tonic-gate 	/* allocate 1394 address for page table */
17837c478bd9Sstevel@tonic-gate 	aa.aa_type = T1394_ADDR_FIXED;
17847c478bd9Sstevel@tonic-gate 	aa.aa_length = len;
17857c478bd9Sstevel@tonic-gate 	aa.aa_address = cmd->sc_pt_dmac.dmac_address;
17867c478bd9Sstevel@tonic-gate 	aa.aa_evts.recv_read_request = NULL;
17877c478bd9Sstevel@tonic-gate 	aa.aa_evts.recv_write_request = NULL;
17887c478bd9Sstevel@tonic-gate 	aa.aa_evts.recv_lock_request = NULL;
17897c478bd9Sstevel@tonic-gate 	aa.aa_arg = NULL;
17907c478bd9Sstevel@tonic-gate 	aa.aa_kmem_bufp = NULL;
17917c478bd9Sstevel@tonic-gate 	aa.aa_enable = T1394_ADDR_RDENBL;
17927c478bd9Sstevel@tonic-gate 	if (t1394_alloc_addr(sp->s_t1394_hdl, &aa, 0, &result) != DDI_SUCCESS) {
17937c478bd9Sstevel@tonic-gate 		(void) ddi_dma_unbind_handle(cmd->sc_pt_dma_hdl);
17947c478bd9Sstevel@tonic-gate 		ddi_dma_mem_free(&cmd->sc_pt_acc_hdl);
17957c478bd9Sstevel@tonic-gate 		ddi_dma_free_handle(&cmd->sc_pt_dma_hdl);
17967c478bd9Sstevel@tonic-gate 		lp->l_stat.stat_err_cmd_pt_addr_alloc++;
17977c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
17987c478bd9Sstevel@tonic-gate 	}
17997c478bd9Sstevel@tonic-gate 	ASSERT(aa.aa_address != 0);
18007c478bd9Sstevel@tonic-gate 	cmd->sc_pt_baddr = aa.aa_address;
18017c478bd9Sstevel@tonic-gate 	cmd->sc_pt_addr_hdl = aa.aa_hdl;
18027c478bd9Sstevel@tonic-gate 
18037c478bd9Sstevel@tonic-gate 	cmd->sc_flags |= SCSA1394_CMD_DMA_BUF_PT_VALID;
18047c478bd9Sstevel@tonic-gate 
18057c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
18067c478bd9Sstevel@tonic-gate }
18077c478bd9Sstevel@tonic-gate 
18087c478bd9Sstevel@tonic-gate static void
scsa1394_cmd_pt_dma_free(scsa1394_state_t * sp,scsa1394_cmd_t * cmd)18097c478bd9Sstevel@tonic-gate scsa1394_cmd_pt_dma_free(scsa1394_state_t *sp, scsa1394_cmd_t *cmd)
18107c478bd9Sstevel@tonic-gate {
18117c478bd9Sstevel@tonic-gate 	(void) ddi_dma_unbind_handle(cmd->sc_pt_dma_hdl);
18127c478bd9Sstevel@tonic-gate 	ddi_dma_mem_free(&cmd->sc_pt_acc_hdl);
18137c478bd9Sstevel@tonic-gate 	ddi_dma_free_handle(&cmd->sc_pt_dma_hdl);
18147c478bd9Sstevel@tonic-gate 	(void) t1394_free_addr(sp->s_t1394_hdl, &cmd->sc_pt_addr_hdl, 0);
18157c478bd9Sstevel@tonic-gate 	cmd->sc_flags &= ~SCSA1394_CMD_DMA_BUF_PT_VALID;
18167c478bd9Sstevel@tonic-gate }
18177c478bd9Sstevel@tonic-gate 
18187c478bd9Sstevel@tonic-gate /*
18197c478bd9Sstevel@tonic-gate  * allocate 1394 addresses for all buffer segments
18207c478bd9Sstevel@tonic-gate  */
18217c478bd9Sstevel@tonic-gate static int
scsa1394_cmd_buf_addr_alloc(scsa1394_state_t * sp,scsa1394_cmd_t * cmd)18227c478bd9Sstevel@tonic-gate scsa1394_cmd_buf_addr_alloc(scsa1394_state_t *sp, scsa1394_cmd_t *cmd)
18237c478bd9Sstevel@tonic-gate {
18247c478bd9Sstevel@tonic-gate 	scsa1394_lun_t	*lp = cmd->sc_lun;
18257c478bd9Sstevel@tonic-gate 	t1394_alloc_addr_t aa;
18267c478bd9Sstevel@tonic-gate 	scsa1394_cmd_seg_t *seg;
18277c478bd9Sstevel@tonic-gate 	int		result;
18287c478bd9Sstevel@tonic-gate 	int		i;
18297c478bd9Sstevel@tonic-gate 
18307c478bd9Sstevel@tonic-gate 	aa.aa_type = T1394_ADDR_FIXED;
18317c478bd9Sstevel@tonic-gate 	aa.aa_evts.recv_read_request = NULL;
18327c478bd9Sstevel@tonic-gate 	aa.aa_evts.recv_write_request = NULL;
18337c478bd9Sstevel@tonic-gate 	aa.aa_evts.recv_lock_request = NULL;
18347c478bd9Sstevel@tonic-gate 	aa.aa_arg = NULL;
18357c478bd9Sstevel@tonic-gate 	aa.aa_kmem_bufp = NULL;
18367c478bd9Sstevel@tonic-gate 	if (cmd->sc_flags & SCSA1394_CMD_READ) {
18377c478bd9Sstevel@tonic-gate 		aa.aa_enable = T1394_ADDR_RDENBL;
18387c478bd9Sstevel@tonic-gate 	} else {
18397c478bd9Sstevel@tonic-gate 		aa.aa_enable = T1394_ADDR_WRENBL;
18407c478bd9Sstevel@tonic-gate 	}
18417c478bd9Sstevel@tonic-gate 
18427c478bd9Sstevel@tonic-gate 	for (i = 0; i < cmd->sc_buf_nsegs; i++) {
18437c478bd9Sstevel@tonic-gate 		seg = &cmd->sc_buf_seg[i];
18447c478bd9Sstevel@tonic-gate 
18457c478bd9Sstevel@tonic-gate 		/* segment bus address */
18467c478bd9Sstevel@tonic-gate 		aa.aa_length = seg->ss_len;
18477c478bd9Sstevel@tonic-gate 		aa.aa_address = seg->ss_daddr;
18487c478bd9Sstevel@tonic-gate 
18497c478bd9Sstevel@tonic-gate 		if (t1394_alloc_addr(sp->s_t1394_hdl, &aa, 0, &result) !=
18507c478bd9Sstevel@tonic-gate 		    DDI_SUCCESS) {
18517c478bd9Sstevel@tonic-gate 			lp->l_stat.stat_err_cmd_buf_addr_alloc++;
18527c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
18537c478bd9Sstevel@tonic-gate 		}
18547c478bd9Sstevel@tonic-gate 		ASSERT(aa.aa_address != 0);
18557c478bd9Sstevel@tonic-gate 		seg->ss_baddr = aa.aa_address;
18567c478bd9Sstevel@tonic-gate 		seg->ss_addr_hdl = aa.aa_hdl;
18577c478bd9Sstevel@tonic-gate 	}
18587c478bd9Sstevel@tonic-gate 
18597c478bd9Sstevel@tonic-gate 	cmd->sc_flags |= SCSA1394_CMD_DMA_BUF_ADDR_VALID;
18607c478bd9Sstevel@tonic-gate 
18617c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
18627c478bd9Sstevel@tonic-gate }
18637c478bd9Sstevel@tonic-gate 
18647c478bd9Sstevel@tonic-gate static void
scsa1394_cmd_buf_addr_free(scsa1394_state_t * sp,scsa1394_cmd_t * cmd)18657c478bd9Sstevel@tonic-gate scsa1394_cmd_buf_addr_free(scsa1394_state_t *sp, scsa1394_cmd_t *cmd)
18667c478bd9Sstevel@tonic-gate {
18677c478bd9Sstevel@tonic-gate 	int		i;
18687c478bd9Sstevel@tonic-gate 
18697c478bd9Sstevel@tonic-gate 	for (i = 0; i < cmd->sc_buf_nsegs; i++) {
18707c478bd9Sstevel@tonic-gate 		if (cmd->sc_buf_seg[i].ss_addr_hdl) {
18717c478bd9Sstevel@tonic-gate 			(void) t1394_free_addr(sp->s_t1394_hdl,
18727c478bd9Sstevel@tonic-gate 			    &cmd->sc_buf_seg[i].ss_addr_hdl, 0);
18737c478bd9Sstevel@tonic-gate 		}
18747c478bd9Sstevel@tonic-gate 	}
18757c478bd9Sstevel@tonic-gate 	cmd->sc_flags &= ~SCSA1394_CMD_DMA_BUF_ADDR_VALID;
18767c478bd9Sstevel@tonic-gate }
18777c478bd9Sstevel@tonic-gate 
18787c478bd9Sstevel@tonic-gate /*
18797c478bd9Sstevel@tonic-gate  * move to next DMA window
18807c478bd9Sstevel@tonic-gate  */
18817c478bd9Sstevel@tonic-gate static int
scsa1394_cmd_buf_dma_move(scsa1394_state_t * sp,scsa1394_cmd_t * cmd)18827c478bd9Sstevel@tonic-gate scsa1394_cmd_buf_dma_move(scsa1394_state_t *sp, scsa1394_cmd_t *cmd)
18837c478bd9Sstevel@tonic-gate {
18847c478bd9Sstevel@tonic-gate 	/* scsa1394_lun_t	*lp = cmd->sc_lun; */
18857c478bd9Sstevel@tonic-gate 	ddi_dma_cookie_t dmac;
18867c478bd9Sstevel@tonic-gate 	uint_t		ccount;
18877c478bd9Sstevel@tonic-gate 
18887c478bd9Sstevel@tonic-gate 	/* for small pkts, leave things where they are (says WDD) */
18897c478bd9Sstevel@tonic-gate 	if ((cmd->sc_curwin == cmd->sc_nwin) && (cmd->sc_nwin == 1)) {
18907c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
18917c478bd9Sstevel@tonic-gate 	}
18927c478bd9Sstevel@tonic-gate 	if (++cmd->sc_curwin >= cmd->sc_nwin) {
18937c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
18947c478bd9Sstevel@tonic-gate 	}
18957c478bd9Sstevel@tonic-gate 	if (ddi_dma_getwin(cmd->sc_buf_dma_hdl, cmd->sc_curwin,
18967c478bd9Sstevel@tonic-gate 	    &cmd->sc_win_offset, &cmd->sc_win_len, &dmac, &ccount) !=
18977c478bd9Sstevel@tonic-gate 	    DDI_SUCCESS) {
18987c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
18997c478bd9Sstevel@tonic-gate 	}
19007c478bd9Sstevel@tonic-gate 
19017c478bd9Sstevel@tonic-gate 	scsa1394_cmd_buf_addr_free(sp, cmd);
19027c478bd9Sstevel@tonic-gate 
19037c478bd9Sstevel@tonic-gate 	/*
19047c478bd9Sstevel@tonic-gate 	 * setup page table if needed
19057c478bd9Sstevel@tonic-gate 	 */
1906f2b7ce3eSartem 	if ((ccount == 1) && (dmac.dmac_size <= SBP2_PT_SEGSIZE_MAX) &&
1907f2b7ce3eSartem 	    (!sp->s_symbios ||
1908f2b7ce3eSartem 	    (dmac.dmac_size <= scsa1394_symbios_page_size))) {
19097c478bd9Sstevel@tonic-gate 		/* but first, free old resources */
19107c478bd9Sstevel@tonic-gate 		if (cmd->sc_flags & SCSA1394_CMD_DMA_BUF_PT_VALID) {
19117c478bd9Sstevel@tonic-gate 			scsa1394_cmd_pt_dma_free(sp, cmd);
19127c478bd9Sstevel@tonic-gate 		}
19137c478bd9Sstevel@tonic-gate 		scsa1394_cmd_seg_free(sp, cmd);
19147c478bd9Sstevel@tonic-gate 
19157c478bd9Sstevel@tonic-gate 		cmd->sc_buf_nsegs = 1;
19167c478bd9Sstevel@tonic-gate 		cmd->sc_buf_seg_mem.ss_len = dmac.dmac_size;
19177c478bd9Sstevel@tonic-gate 		cmd->sc_buf_seg_mem.ss_daddr = dmac.dmac_address;
19187c478bd9Sstevel@tonic-gate 		cmd->sc_buf_seg = &cmd->sc_buf_seg_mem;
19197c478bd9Sstevel@tonic-gate 	} else {
19207c478bd9Sstevel@tonic-gate 		/* break window into segments */
19217c478bd9Sstevel@tonic-gate 		if (scsa1394_cmd_dmac2seg(sp, cmd, &dmac, ccount, KM_NOSLEEP) !=
19227c478bd9Sstevel@tonic-gate 		    DDI_SUCCESS) {
19237c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
19247c478bd9Sstevel@tonic-gate 		}
19257c478bd9Sstevel@tonic-gate 
19267c478bd9Sstevel@tonic-gate 		/* allocate DMA resources */
19277c478bd9Sstevel@tonic-gate 		if (scsa1394_cmd_pt_dma_alloc(sp, cmd, NULL_FUNC, NULL,
19287c478bd9Sstevel@tonic-gate 		    cmd->sc_buf_nsegs) != DDI_SUCCESS) {
19297c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
19307c478bd9Sstevel@tonic-gate 		}
19317c478bd9Sstevel@tonic-gate 	}
19327c478bd9Sstevel@tonic-gate 
19337c478bd9Sstevel@tonic-gate 	/* allocate 1394 addresses for segments */
19347c478bd9Sstevel@tonic-gate 	if (scsa1394_cmd_buf_addr_alloc(sp, cmd) != DDI_SUCCESS) {
19357c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
19367c478bd9Sstevel@tonic-gate 	}
19377c478bd9Sstevel@tonic-gate 
19387c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
19397c478bd9Sstevel@tonic-gate }
19407c478bd9Sstevel@tonic-gate 
19417c478bd9Sstevel@tonic-gate /*
19427c478bd9Sstevel@tonic-gate  *
19437c478bd9Sstevel@tonic-gate  * --- pkt and data transfer routines
19447c478bd9Sstevel@tonic-gate  *
19457c478bd9Sstevel@tonic-gate  */
19467c478bd9Sstevel@tonic-gate static int
scsa1394_scsi_start(struct scsi_address * ap,struct scsi_pkt * pkt)19477c478bd9Sstevel@tonic-gate scsa1394_scsi_start(struct scsi_address *ap, struct scsi_pkt *pkt)
19487c478bd9Sstevel@tonic-gate {
19497c478bd9Sstevel@tonic-gate 	scsa1394_state_t *sp = ADDR2STATE(ap);
19507c478bd9Sstevel@tonic-gate 	scsa1394_cmd_t	*cmd = PKT2CMD(pkt);
19517c478bd9Sstevel@tonic-gate 	scsa1394_lun_t	*lp = cmd->sc_lun;
19527c478bd9Sstevel@tonic-gate 	int		ret;
19537c478bd9Sstevel@tonic-gate 
19547c478bd9Sstevel@tonic-gate 	/*
19557c478bd9Sstevel@tonic-gate 	 * since we don't support polled I/O, just accept the packet
19567c478bd9Sstevel@tonic-gate 	 * so the rest of the file systems get synced properly
19577c478bd9Sstevel@tonic-gate 	 */
19587c478bd9Sstevel@tonic-gate 	if (ddi_in_panic()) {
19597c478bd9Sstevel@tonic-gate 		scsa1394_prepare_pkt(sp, pkt);
19607c478bd9Sstevel@tonic-gate 		return (TRAN_ACCEPT);
19617c478bd9Sstevel@tonic-gate 	}
19627c478bd9Sstevel@tonic-gate 
19637c478bd9Sstevel@tonic-gate 	/* polling not supported yet */
19647c478bd9Sstevel@tonic-gate 	if (pkt->pkt_flags & FLAG_NOINTR) {
19657c478bd9Sstevel@tonic-gate 		return (TRAN_BADPKT);
19667c478bd9Sstevel@tonic-gate 	}
19677c478bd9Sstevel@tonic-gate 
1968f2b7ce3eSartem 	mutex_enter(&sp->s_mutex);
1969f2b7ce3eSartem 	if (sp->s_dev_state != SCSA1394_DEV_ONLINE) {
1970f2b7ce3eSartem 		/*
1971f2b7ce3eSartem 		 * If device is temporarily gone due to bus reset,
1972f2b7ce3eSartem 		 * return busy to prevent prevent scary console messages.
1973f2b7ce3eSartem 		 * If permanently gone, leave it to scsa1394_cmd_fake_comp().
1974f2b7ce3eSartem 		 */
1975f2b7ce3eSartem 		if (sp->s_dev_state == SCSA1394_DEV_BUS_RESET) {
1976f2b7ce3eSartem 			mutex_exit(&sp->s_mutex);
1977f2b7ce3eSartem 			return (TRAN_BUSY);
1978f2b7ce3eSartem 		}
1979f2b7ce3eSartem 	}
1980f2b7ce3eSartem 	mutex_exit(&sp->s_mutex);
1981f2b7ce3eSartem 
19827c478bd9Sstevel@tonic-gate 	if ((ap->a_lun >= sp->s_nluns) ||
19837c478bd9Sstevel@tonic-gate 	    (ap->a_lun != pkt->pkt_address.a_lun)) {
19847c478bd9Sstevel@tonic-gate 		return (TRAN_BADPKT);
19857c478bd9Sstevel@tonic-gate 	}
19867c478bd9Sstevel@tonic-gate 
19877c478bd9Sstevel@tonic-gate 	scsa1394_prepare_pkt(sp, pkt);
19887c478bd9Sstevel@tonic-gate 
19897c478bd9Sstevel@tonic-gate 	/* some commands may require fake completion */
19907c478bd9Sstevel@tonic-gate 	if ((ret = scsa1394_cmd_fake_comp(sp, cmd)) == DDI_SUCCESS) {
19917c478bd9Sstevel@tonic-gate 		return (TRAN_ACCEPT);
19927c478bd9Sstevel@tonic-gate 	}
19937c478bd9Sstevel@tonic-gate 
19947c478bd9Sstevel@tonic-gate 	scsa1394_cmd_fill_cdb(lp, cmd);
19957c478bd9Sstevel@tonic-gate 
19967c478bd9Sstevel@tonic-gate 	if (cmd->sc_flags & SCSA1394_CMD_DMA_BUF_PT_VALID) {
19977c478bd9Sstevel@tonic-gate 		scsa1394_sbp2_seg2pt(lp, cmd);
19987c478bd9Sstevel@tonic-gate 	}
19997c478bd9Sstevel@tonic-gate 
20007c478bd9Sstevel@tonic-gate 	scsa1394_sbp2_cmd2orb(lp, cmd);		/* convert into ORB */
20017c478bd9Sstevel@tonic-gate 
20028c067cfdSAlan Perry 	if ((ret = scsa1394_sbp2_start(lp, cmd)) != TRAN_BUSY) {
20037c478bd9Sstevel@tonic-gate 		scsa1394_sbp2_nudge(lp);
20047c478bd9Sstevel@tonic-gate 	}
20057c478bd9Sstevel@tonic-gate 
20067c478bd9Sstevel@tonic-gate 	return (ret);
20077c478bd9Sstevel@tonic-gate }
20087c478bd9Sstevel@tonic-gate 
20097c478bd9Sstevel@tonic-gate /*ARGSUSED*/
20107c478bd9Sstevel@tonic-gate static void
scsa1394_prepare_pkt(scsa1394_state_t * sp,struct scsi_pkt * pkt)20117c478bd9Sstevel@tonic-gate scsa1394_prepare_pkt(scsa1394_state_t *sp, struct scsi_pkt *pkt)
20127c478bd9Sstevel@tonic-gate {
20137c478bd9Sstevel@tonic-gate 	scsa1394_cmd_t	*cmd = PKT2CMD(pkt);
20147c478bd9Sstevel@tonic-gate 
20157c478bd9Sstevel@tonic-gate 	pkt->pkt_reason = CMD_CMPLT;
20167c478bd9Sstevel@tonic-gate 	pkt->pkt_state = 0;
20177c478bd9Sstevel@tonic-gate 	pkt->pkt_statistics = 0;
20187c478bd9Sstevel@tonic-gate 	*(pkt->pkt_scbp) = STATUS_GOOD;
20197c478bd9Sstevel@tonic-gate 
20207c478bd9Sstevel@tonic-gate 	if (cmd) {
20217c478bd9Sstevel@tonic-gate 		cmd->sc_timeout = pkt->pkt_time;
20227c478bd9Sstevel@tonic-gate 
20237c478bd9Sstevel@tonic-gate 		/* workarounds */
20247c478bd9Sstevel@tonic-gate 		switch (pkt->pkt_cdbp[0]) {
20257c478bd9Sstevel@tonic-gate 		/*
20267c478bd9Sstevel@tonic-gate 		 * sd does START_STOP_UNIT during attach with a 200 sec timeout.
20277c478bd9Sstevel@tonic-gate 		 * at this time devi_lock is held, prtconf will be stuck.
20287c478bd9Sstevel@tonic-gate 		 * reduce timeout for the time being.
20297c478bd9Sstevel@tonic-gate 		 */
20307c478bd9Sstevel@tonic-gate 		case SCMD_START_STOP:
20317c478bd9Sstevel@tonic-gate 			cmd->sc_timeout = min(cmd->sc_timeout,
20327c478bd9Sstevel@tonic-gate 			    scsa1394_start_stop_timeout_max);
20337c478bd9Sstevel@tonic-gate 			break;
20347c478bd9Sstevel@tonic-gate 		default:
20357c478bd9Sstevel@tonic-gate 			break;
20367c478bd9Sstevel@tonic-gate 		}
20377c478bd9Sstevel@tonic-gate 	}
20387c478bd9Sstevel@tonic-gate }
20397c478bd9Sstevel@tonic-gate 
20407c478bd9Sstevel@tonic-gate static void
scsa1394_cmd_fill_cdb(scsa1394_lun_t * lp,scsa1394_cmd_t * cmd)20417c478bd9Sstevel@tonic-gate scsa1394_cmd_fill_cdb(scsa1394_lun_t *lp, scsa1394_cmd_t *cmd)
20427c478bd9Sstevel@tonic-gate {
20437c478bd9Sstevel@tonic-gate 	cmd->sc_cdb_actual_len = cmd->sc_cdb_len;
20447c478bd9Sstevel@tonic-gate 
20457c478bd9Sstevel@tonic-gate 	mutex_enter(&lp->l_mutex);
20467c478bd9Sstevel@tonic-gate 
20477c478bd9Sstevel@tonic-gate 	switch (lp->l_dtype_orig) {
20487c478bd9Sstevel@tonic-gate 	case DTYPE_DIRECT:
20497c478bd9Sstevel@tonic-gate 	case DTYPE_RODIRECT:
20507c478bd9Sstevel@tonic-gate 	case DTYPE_OPTICAL:
20517c478bd9Sstevel@tonic-gate 	case SCSA1394_DTYPE_RBC:
20527c478bd9Sstevel@tonic-gate 		scsa1394_cmd_fill_cdb_rbc(lp, cmd);
20537c478bd9Sstevel@tonic-gate 		break;
20547c478bd9Sstevel@tonic-gate 	default:
20557c478bd9Sstevel@tonic-gate 		scsa1394_cmd_fill_cdb_other(lp, cmd);
20567c478bd9Sstevel@tonic-gate 		break;
20577c478bd9Sstevel@tonic-gate 	}
20587c478bd9Sstevel@tonic-gate 
20597c478bd9Sstevel@tonic-gate 	mutex_exit(&lp->l_mutex);
20607c478bd9Sstevel@tonic-gate }
20617c478bd9Sstevel@tonic-gate 
20627c478bd9Sstevel@tonic-gate static void
scsa1394_cmd_fill_cdb_rbc(scsa1394_lun_t * lp,scsa1394_cmd_t * cmd)20637c478bd9Sstevel@tonic-gate scsa1394_cmd_fill_cdb_rbc(scsa1394_lun_t *lp, scsa1394_cmd_t *cmd)
20647c478bd9Sstevel@tonic-gate {
20657c478bd9Sstevel@tonic-gate 	scsa1394_state_t *sp = lp->l_sp;
20667c478bd9Sstevel@tonic-gate 	struct scsi_pkt	*pkt = CMD2PKT(cmd);
20677c478bd9Sstevel@tonic-gate 	int		lba, opcode;
20687c478bd9Sstevel@tonic-gate 	struct buf	*bp = cmd->sc_bp;
20697c478bd9Sstevel@tonic-gate 	size_t		len;
20707c478bd9Sstevel@tonic-gate 	size_t		blk_size;
20717c478bd9Sstevel@tonic-gate 	int		sz;
20727c478bd9Sstevel@tonic-gate 
20737c478bd9Sstevel@tonic-gate 	opcode = pkt->pkt_cdbp[0];
20747c478bd9Sstevel@tonic-gate 	blk_size  = lp->l_lba_size;
20757c478bd9Sstevel@tonic-gate 
20767c478bd9Sstevel@tonic-gate 	switch (opcode) {
20777c478bd9Sstevel@tonic-gate 	case SCMD_READ:
20787c478bd9Sstevel@tonic-gate 		/* RBC only supports 10-byte read/write */
20797c478bd9Sstevel@tonic-gate 		lba = SCSA1394_LBA_6BYTE(pkt);
20807c478bd9Sstevel@tonic-gate 		len = SCSA1394_LEN_6BYTE(pkt);
20817c478bd9Sstevel@tonic-gate 		opcode = SCMD_READ_G1;
20827c478bd9Sstevel@tonic-gate 		cmd->sc_cdb_actual_len = CDB_GROUP1;
20837c478bd9Sstevel@tonic-gate 		break;
20847c478bd9Sstevel@tonic-gate 	case SCMD_WRITE:
20857c478bd9Sstevel@tonic-gate 		lba = SCSA1394_LBA_6BYTE(pkt);
20867c478bd9Sstevel@tonic-gate 		len = SCSA1394_LEN_6BYTE(pkt);
20877c478bd9Sstevel@tonic-gate 		opcode = SCMD_WRITE_G1;
20887c478bd9Sstevel@tonic-gate 		cmd->sc_cdb_actual_len = CDB_GROUP1;
20897c478bd9Sstevel@tonic-gate 		break;
20907c478bd9Sstevel@tonic-gate 	case SCMD_READ_G1:
20917c478bd9Sstevel@tonic-gate 	case SCMD_READ_LONG:
20927c478bd9Sstevel@tonic-gate 		lba = SCSA1394_LBA_10BYTE(pkt);
20937c478bd9Sstevel@tonic-gate 		len = SCSA1394_LEN_10BYTE(pkt);
20947c478bd9Sstevel@tonic-gate 		break;
20957c478bd9Sstevel@tonic-gate 	case SCMD_WRITE_G1:
20967c478bd9Sstevel@tonic-gate 	case SCMD_WRITE_LONG:
20977c478bd9Sstevel@tonic-gate 		lba = SCSA1394_LBA_10BYTE(pkt);
20987c478bd9Sstevel@tonic-gate 		len = SCSA1394_LEN_10BYTE(pkt);
2099f2b7ce3eSartem 		if ((lp->l_dtype_orig == DTYPE_RODIRECT) &&
2100f2b7ce3eSartem 		    (bp != NULL) && (len != 0)) {
2101f2b7ce3eSartem 			sz = SCSA1394_CDRW_BLKSZ(bp->b_bcount, len);
2102f2b7ce3eSartem 			if (SCSA1394_VALID_CDRW_BLKSZ(sz)) {
2103f2b7ce3eSartem 				blk_size = sz;
2104f2b7ce3eSartem 			}
21057c478bd9Sstevel@tonic-gate 		}
21067c478bd9Sstevel@tonic-gate 		break;
21077c478bd9Sstevel@tonic-gate 	case SCMD_READ_CD:
21087c478bd9Sstevel@tonic-gate 		lba = SCSA1394_LBA_10BYTE(pkt);
21097c478bd9Sstevel@tonic-gate 		len = SCSA1394_LEN_READ_CD(pkt);
21107c478bd9Sstevel@tonic-gate 		blk_size = scsa1394_cmd_read_cd_blk_size(pkt->pkt_cdbp[1] >> 2);
21117c478bd9Sstevel@tonic-gate 		break;
21127c478bd9Sstevel@tonic-gate 	case SCMD_READ_G5:
21137c478bd9Sstevel@tonic-gate 		lba = SCSA1394_LBA_12BYTE(pkt);
21147c478bd9Sstevel@tonic-gate 		len = SCSA1394_LEN_12BYTE(pkt);
21157c478bd9Sstevel@tonic-gate 		break;
21167c478bd9Sstevel@tonic-gate 	case SCMD_WRITE_G5:
21177c478bd9Sstevel@tonic-gate 		lba = SCSA1394_LBA_12BYTE(pkt);
21187c478bd9Sstevel@tonic-gate 		len = SCSA1394_LEN_12BYTE(pkt);
21197c478bd9Sstevel@tonic-gate 		break;
21207c478bd9Sstevel@tonic-gate 	default:
21217c478bd9Sstevel@tonic-gate 		/* no special mapping for other commands */
21227c478bd9Sstevel@tonic-gate 		scsa1394_cmd_fill_cdb_other(lp, cmd);
21237c478bd9Sstevel@tonic-gate 		return;
21247c478bd9Sstevel@tonic-gate 	}
2125f2b7ce3eSartem 	cmd->sc_blk_size = blk_size;
21267c478bd9Sstevel@tonic-gate 
21277c478bd9Sstevel@tonic-gate 	/* limit xfer length for Symbios workaround */
21287c478bd9Sstevel@tonic-gate 	if (sp->s_symbios && (len * blk_size > scsa1394_symbios_size_max)) {
21297c478bd9Sstevel@tonic-gate 		cmd->sc_flags |= SCSA1394_CMD_SYMBIOS_BREAKUP;
21307c478bd9Sstevel@tonic-gate 
21317c478bd9Sstevel@tonic-gate 		cmd->sc_total_blks = cmd->sc_resid_blks = len;
21327c478bd9Sstevel@tonic-gate 
21337c478bd9Sstevel@tonic-gate 		len = scsa1394_symbios_size_max / blk_size;
21347c478bd9Sstevel@tonic-gate 	}
21357c478bd9Sstevel@tonic-gate 	cmd->sc_xfer_blks = len;
21367c478bd9Sstevel@tonic-gate 	cmd->sc_xfer_bytes = len * blk_size;
21377c478bd9Sstevel@tonic-gate 
21387c478bd9Sstevel@tonic-gate 	/* finalize new CDB */
2139a888983fSap 	switch (pkt->pkt_cdbp[0]) {
2140a888983fSap 	case SCMD_READ:
2141a888983fSap 	case SCMD_WRITE:
2142a888983fSap 		/*
2143a888983fSap 		 * We rewrite READ/WRITE G0 commands as READ/WRITE G1.
2144a888983fSap 		 * Build new cdb from scatch.
2145a888983fSap 		 * The lba and length fields is updated below.
2146a888983fSap 		 */
2147a888983fSap 		bzero(cmd->sc_cdb, cmd->sc_cdb_actual_len);
2148a888983fSap 		break;
2149a888983fSap 	default:
2150a888983fSap 		/*
2151a888983fSap 		 * Copy the non lba/len fields.
2152a888983fSap 		 * The lba and length fields is updated below.
2153a888983fSap 		 */
2154a888983fSap 		bcopy(pkt->pkt_cdbp, cmd->sc_cdb, cmd->sc_cdb_actual_len);
2155a888983fSap 		break;
2156a888983fSap 	}
2157a888983fSap 
21587c478bd9Sstevel@tonic-gate 	cmd->sc_cdb[0] = (uchar_t)opcode;
21597c478bd9Sstevel@tonic-gate 	scsa1394_cmd_fill_cdb_lba(cmd, lba);
21607c478bd9Sstevel@tonic-gate 	switch (opcode) {
21617c478bd9Sstevel@tonic-gate 	case SCMD_READ_CD:
21627c478bd9Sstevel@tonic-gate 		scsa1394_cmd_fill_read_cd_cdb_len(cmd, len);
21637c478bd9Sstevel@tonic-gate 		break;
21647c478bd9Sstevel@tonic-gate 	case SCMD_WRITE_G5:
21657c478bd9Sstevel@tonic-gate 	case SCMD_READ_G5:
21667c478bd9Sstevel@tonic-gate 		scsa1394_cmd_fill_12byte_cdb_len(cmd, len);
21677c478bd9Sstevel@tonic-gate 		break;
21687c478bd9Sstevel@tonic-gate 	default:
21697c478bd9Sstevel@tonic-gate 		scsa1394_cmd_fill_cdb_len(cmd, len);
21707c478bd9Sstevel@tonic-gate 		break;
21717c478bd9Sstevel@tonic-gate 	}
21727c478bd9Sstevel@tonic-gate }
21737c478bd9Sstevel@tonic-gate 
21747c478bd9Sstevel@tonic-gate /*ARGSUSED*/
21757c478bd9Sstevel@tonic-gate static void
scsa1394_cmd_fill_cdb_other(scsa1394_lun_t * lp,scsa1394_cmd_t * cmd)21767c478bd9Sstevel@tonic-gate scsa1394_cmd_fill_cdb_other(scsa1394_lun_t *lp, scsa1394_cmd_t *cmd)
21777c478bd9Sstevel@tonic-gate {
21787c478bd9Sstevel@tonic-gate 	struct scsi_pkt	*pkt = CMD2PKT(cmd);
21797c478bd9Sstevel@tonic-gate 
21807c478bd9Sstevel@tonic-gate 	cmd->sc_xfer_bytes = cmd->sc_win_len;
2181f2b7ce3eSartem 	cmd->sc_xfer_blks = cmd->sc_xfer_bytes / lp->l_lba_size;
2182f2b7ce3eSartem 	cmd->sc_total_blks = cmd->sc_xfer_blks;
2183f2b7ce3eSartem 	cmd->sc_lba = 0;
2184f2b7ce3eSartem 
2185f2b7ce3eSartem 	bcopy(pkt->pkt_cdbp, cmd->sc_cdb, cmd->sc_cdb_len);
21867c478bd9Sstevel@tonic-gate }
21877c478bd9Sstevel@tonic-gate 
21887c478bd9Sstevel@tonic-gate /*
21897c478bd9Sstevel@tonic-gate  * fill up parts of CDB
21907c478bd9Sstevel@tonic-gate  */
21917c478bd9Sstevel@tonic-gate static void
scsa1394_cmd_fill_cdb_len(scsa1394_cmd_t * cmd,int len)21927c478bd9Sstevel@tonic-gate scsa1394_cmd_fill_cdb_len(scsa1394_cmd_t *cmd, int len)
21937c478bd9Sstevel@tonic-gate {
21947c478bd9Sstevel@tonic-gate 	cmd->sc_cdb[7] = len >> 8;
21957c478bd9Sstevel@tonic-gate 	cmd->sc_cdb[8] = (uchar_t)len;
21967c478bd9Sstevel@tonic-gate }
21977c478bd9Sstevel@tonic-gate 
21987c478bd9Sstevel@tonic-gate static void
scsa1394_cmd_fill_cdb_lba(scsa1394_cmd_t * cmd,int lba)21997c478bd9Sstevel@tonic-gate scsa1394_cmd_fill_cdb_lba(scsa1394_cmd_t *cmd, int lba)
22007c478bd9Sstevel@tonic-gate {
22017c478bd9Sstevel@tonic-gate 	cmd->sc_cdb[2] = lba >> 24;
22027c478bd9Sstevel@tonic-gate 	cmd->sc_cdb[3] = lba >> 16;
22037c478bd9Sstevel@tonic-gate 	cmd->sc_cdb[4] = lba >> 8;
22047c478bd9Sstevel@tonic-gate 	cmd->sc_cdb[5] = (uchar_t)lba;
22057c478bd9Sstevel@tonic-gate 	cmd->sc_lba = lba;
22067c478bd9Sstevel@tonic-gate }
22077c478bd9Sstevel@tonic-gate 
22087c478bd9Sstevel@tonic-gate static void
scsa1394_cmd_fill_12byte_cdb_len(scsa1394_cmd_t * cmd,int len)22097c478bd9Sstevel@tonic-gate scsa1394_cmd_fill_12byte_cdb_len(scsa1394_cmd_t *cmd, int len)
22107c478bd9Sstevel@tonic-gate {
22117c478bd9Sstevel@tonic-gate 	cmd->sc_cdb[6] = len >> 24;
22127c478bd9Sstevel@tonic-gate 	cmd->sc_cdb[7] = len >> 16;
22137c478bd9Sstevel@tonic-gate 	cmd->sc_cdb[8] = len >> 8;
22147c478bd9Sstevel@tonic-gate 	cmd->sc_cdb[9] = (uchar_t)len;
22157c478bd9Sstevel@tonic-gate }
22167c478bd9Sstevel@tonic-gate 
22177c478bd9Sstevel@tonic-gate static void
scsa1394_cmd_fill_read_cd_cdb_len(scsa1394_cmd_t * cmd,int len)22187c478bd9Sstevel@tonic-gate scsa1394_cmd_fill_read_cd_cdb_len(scsa1394_cmd_t *cmd, int len)
22197c478bd9Sstevel@tonic-gate {
22207c478bd9Sstevel@tonic-gate 	cmd->sc_cdb[6] = len >> 16;
22217c478bd9Sstevel@tonic-gate 	cmd->sc_cdb[7] = len >> 8;
22227c478bd9Sstevel@tonic-gate 	cmd->sc_cdb[8] = (uchar_t)len;
22237c478bd9Sstevel@tonic-gate }
22247c478bd9Sstevel@tonic-gate 
22257c478bd9Sstevel@tonic-gate /*
22267c478bd9Sstevel@tonic-gate  * For SCMD_READ_CD, figure out the block size based on expected sector type.
22277c478bd9Sstevel@tonic-gate  * See MMC SCSI Specs section 6.1.15
22287c478bd9Sstevel@tonic-gate  */
22297c478bd9Sstevel@tonic-gate static int
scsa1394_cmd_read_cd_blk_size(uchar_t expected_sector_type)22307c478bd9Sstevel@tonic-gate scsa1394_cmd_read_cd_blk_size(uchar_t expected_sector_type)
22317c478bd9Sstevel@tonic-gate {
22327c478bd9Sstevel@tonic-gate 	int blk_size;
22337c478bd9Sstevel@tonic-gate 
22347c478bd9Sstevel@tonic-gate 	switch (expected_sector_type) {
22357c478bd9Sstevel@tonic-gate 	case READ_CD_EST_CDDA:
22367c478bd9Sstevel@tonic-gate 		blk_size = CDROM_BLK_2352;
22377c478bd9Sstevel@tonic-gate 		break;
22387c478bd9Sstevel@tonic-gate 	case READ_CD_EST_MODE2:
22397c478bd9Sstevel@tonic-gate 		blk_size = CDROM_BLK_2336;
22407c478bd9Sstevel@tonic-gate 		break;
22417c478bd9Sstevel@tonic-gate 	case READ_CD_EST_MODE2FORM2:
22427c478bd9Sstevel@tonic-gate 		blk_size = CDROM_BLK_2324;
22437c478bd9Sstevel@tonic-gate 		break;
22447c478bd9Sstevel@tonic-gate 	case READ_CD_EST_MODE2FORM1:
22457c478bd9Sstevel@tonic-gate 	case READ_CD_EST_ALLTYPE:
22467c478bd9Sstevel@tonic-gate 	case READ_CD_EST_MODE1:
22477c478bd9Sstevel@tonic-gate 	default:
22487c478bd9Sstevel@tonic-gate 		blk_size = CDROM_BLK_2048;
22497c478bd9Sstevel@tonic-gate 	}
22507c478bd9Sstevel@tonic-gate 
22517c478bd9Sstevel@tonic-gate 	return (blk_size);
22527c478bd9Sstevel@tonic-gate }
22537c478bd9Sstevel@tonic-gate 
22547c478bd9Sstevel@tonic-gate /*ARGSUSED*/
22557c478bd9Sstevel@tonic-gate static int
scsa1394_cmd_fake_mode_sense(scsa1394_state_t * sp,scsa1394_cmd_t * cmd)22567c478bd9Sstevel@tonic-gate scsa1394_cmd_fake_mode_sense(scsa1394_state_t *sp, scsa1394_cmd_t *cmd)
22577c478bd9Sstevel@tonic-gate {
22587c478bd9Sstevel@tonic-gate 	struct scsi_pkt	*pkt = CMD2PKT(cmd);
22597c478bd9Sstevel@tonic-gate 	struct scsi_arq_status *arqp = (struct scsi_arq_status *)pkt->pkt_scbp;
22607c478bd9Sstevel@tonic-gate 	struct scsi_extended_sense *esp = &arqp->sts_sensedata;
22617c478bd9Sstevel@tonic-gate 
22627c478bd9Sstevel@tonic-gate 	*(pkt->pkt_scbp) = STATUS_CHECK;
22637c478bd9Sstevel@tonic-gate 	*(uint8_t *)&arqp->sts_rqpkt_status = STATUS_GOOD;
22647c478bd9Sstevel@tonic-gate 	arqp->sts_rqpkt_reason = CMD_CMPLT;
22657c478bd9Sstevel@tonic-gate 	arqp->sts_rqpkt_resid = 0;
22667c478bd9Sstevel@tonic-gate 	arqp->sts_rqpkt_state |= STATE_XFERRED_DATA;
22677c478bd9Sstevel@tonic-gate 	arqp->sts_rqpkt_statistics = 0;
22687c478bd9Sstevel@tonic-gate 
22697c478bd9Sstevel@tonic-gate 	bzero(esp, sizeof (struct scsi_extended_sense));
22707c478bd9Sstevel@tonic-gate 
22717c478bd9Sstevel@tonic-gate 	esp->es_class = CLASS_EXTENDED_SENSE;
22727c478bd9Sstevel@tonic-gate 
22737c478bd9Sstevel@tonic-gate 	esp->es_key = KEY_ILLEGAL_REQUEST;
22747c478bd9Sstevel@tonic-gate 
22757c478bd9Sstevel@tonic-gate 	pkt->pkt_reason = CMD_CMPLT;
22767c478bd9Sstevel@tonic-gate 	pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET | STATE_SENT_CMD |
22777c478bd9Sstevel@tonic-gate 	    STATE_XFERRED_DATA | STATE_GOT_STATUS);
22787c478bd9Sstevel@tonic-gate 
22797c478bd9Sstevel@tonic-gate 	if (pkt->pkt_comp) {
22807c478bd9Sstevel@tonic-gate 		(*pkt->pkt_comp)(pkt);
22817c478bd9Sstevel@tonic-gate 	}
22827c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
22837c478bd9Sstevel@tonic-gate }
22847c478bd9Sstevel@tonic-gate 
22857c478bd9Sstevel@tonic-gate /*ARGSUSED*/
22867c478bd9Sstevel@tonic-gate static int
scsa1394_cmd_fake_inquiry(scsa1394_state_t * sp,scsa1394_cmd_t * cmd)22877c478bd9Sstevel@tonic-gate scsa1394_cmd_fake_inquiry(scsa1394_state_t *sp, scsa1394_cmd_t *cmd)
22887c478bd9Sstevel@tonic-gate {
22897c478bd9Sstevel@tonic-gate 	scsa1394_lun_t	*lp = cmd->sc_lun;
22907c478bd9Sstevel@tonic-gate 	struct scsi_pkt	*pkt = CMD2PKT(cmd);
22917c478bd9Sstevel@tonic-gate 	struct scsi_inquiry *inq;
22927c478bd9Sstevel@tonic-gate 
22937c478bd9Sstevel@tonic-gate 	/* copy fabricated inquiry data */
22947c478bd9Sstevel@tonic-gate 	inq = (struct scsi_inquiry *)cmd->sc_bp->b_un.b_addr;
22957c478bd9Sstevel@tonic-gate 	bcopy(&lp->l_fake_inq, inq, sizeof (struct scsi_inquiry));
22967c478bd9Sstevel@tonic-gate 
22977c478bd9Sstevel@tonic-gate 	pkt->pkt_resid -= sizeof (struct scsi_inquiry);
22987c478bd9Sstevel@tonic-gate 	pkt->pkt_reason = CMD_CMPLT;
22997c478bd9Sstevel@tonic-gate 	pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET | STATE_SENT_CMD |
23007c478bd9Sstevel@tonic-gate 	    STATE_XFERRED_DATA | STATE_GOT_STATUS);
23017c478bd9Sstevel@tonic-gate 
23027c478bd9Sstevel@tonic-gate 	if (pkt->pkt_comp) {
23037c478bd9Sstevel@tonic-gate 		(*pkt->pkt_comp)(pkt);
23047c478bd9Sstevel@tonic-gate 	}
23057c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
23067c478bd9Sstevel@tonic-gate }
23077c478bd9Sstevel@tonic-gate 
23087c478bd9Sstevel@tonic-gate /*
23097c478bd9Sstevel@tonic-gate  * If command allows fake completion (without actually being transported),
23107c478bd9Sstevel@tonic-gate  * call completion callback and return DDI_SUCCESS.
23117c478bd9Sstevel@tonic-gate  * Otherwise return DDI_FAILURE.
23127c478bd9Sstevel@tonic-gate  */
23137c478bd9Sstevel@tonic-gate static int
scsa1394_cmd_fake_comp(scsa1394_state_t * sp,scsa1394_cmd_t * cmd)23147c478bd9Sstevel@tonic-gate scsa1394_cmd_fake_comp(scsa1394_state_t *sp, scsa1394_cmd_t *cmd)
23157c478bd9Sstevel@tonic-gate {
23167c478bd9Sstevel@tonic-gate 	struct scsi_pkt	*pkt = CMD2PKT(cmd);
23177c478bd9Sstevel@tonic-gate 	scsa1394_lun_t	*lp = cmd->sc_lun;
23187c478bd9Sstevel@tonic-gate 	int		ret = DDI_SUCCESS;
23197c478bd9Sstevel@tonic-gate 
2320f2b7ce3eSartem 	/*
2321f2b7ce3eSartem 	 * agreement with sd in case of device hot removal
2322f2b7ce3eSartem 	 * is to fake completion with CMD_DEV_GONE
2323f2b7ce3eSartem 	 */
2324f2b7ce3eSartem 	mutex_enter(&sp->s_mutex);
2325f2b7ce3eSartem 	if (sp->s_dev_state != SCSA1394_DEV_ONLINE) {
2326f2b7ce3eSartem 		mutex_exit(&sp->s_mutex);
2327f2b7ce3eSartem 		pkt->pkt_reason = CMD_DEV_GONE;
2328f2b7ce3eSartem 		if (pkt->pkt_comp) {
2329f2b7ce3eSartem 			(*pkt->pkt_comp)(pkt);
2330f2b7ce3eSartem 		}
2331f2b7ce3eSartem 		return (DDI_SUCCESS);
2332f2b7ce3eSartem 	}
2333f2b7ce3eSartem 	mutex_exit(&sp->s_mutex);
2334f2b7ce3eSartem 
23357c478bd9Sstevel@tonic-gate 	mutex_enter(&lp->l_mutex);
23367c478bd9Sstevel@tonic-gate 
23377c478bd9Sstevel@tonic-gate 	switch (pkt->pkt_cdbp[0]) {
23387c478bd9Sstevel@tonic-gate 	/*
23397c478bd9Sstevel@tonic-gate 	 * RBC support for PRIN/PROUT is optional
23407c478bd9Sstevel@tonic-gate 	 */
23417c478bd9Sstevel@tonic-gate 	case SCMD_PRIN:
23427c478bd9Sstevel@tonic-gate 	case SCMD_PROUT:
23437c478bd9Sstevel@tonic-gate 		if (!scsa1394_wrka_fake_prin) {
23447c478bd9Sstevel@tonic-gate 			ret = DDI_FAILURE;
23457c478bd9Sstevel@tonic-gate 		}
23467c478bd9Sstevel@tonic-gate 		break;
23477c478bd9Sstevel@tonic-gate 	/*
23487c478bd9Sstevel@tonic-gate 	 * Some fixed disks don't like doorlock cmd. And they don't need it.
23497c478bd9Sstevel@tonic-gate 	 */
23507c478bd9Sstevel@tonic-gate 	case SCMD_DOORLOCK:
23517c478bd9Sstevel@tonic-gate 		if (lp->l_rmb_orig != 0) {
23527c478bd9Sstevel@tonic-gate 			ret = DDI_FAILURE;
23537c478bd9Sstevel@tonic-gate 		}
23547c478bd9Sstevel@tonic-gate 		break;
23557c478bd9Sstevel@tonic-gate 	case SCMD_TEST_UNIT_READY:
23567c478bd9Sstevel@tonic-gate 		if (!lp->l_nosup_tur) {
23577c478bd9Sstevel@tonic-gate 			ret = DDI_FAILURE;
23587c478bd9Sstevel@tonic-gate 		}
23597c478bd9Sstevel@tonic-gate 		break;
23607c478bd9Sstevel@tonic-gate 	case SCMD_START_STOP:
23617c478bd9Sstevel@tonic-gate 		if (!lp->l_nosup_start_stop) {
23627c478bd9Sstevel@tonic-gate 			ret = DDI_FAILURE;
23637c478bd9Sstevel@tonic-gate 		}
23647c478bd9Sstevel@tonic-gate 		break;
23657c478bd9Sstevel@tonic-gate 	case SCMD_INQUIRY:
23667c478bd9Sstevel@tonic-gate 		if (!lp->l_nosup_inquiry) {
23677c478bd9Sstevel@tonic-gate 			ret = DDI_FAILURE;
23687c478bd9Sstevel@tonic-gate 		} else {
23697c478bd9Sstevel@tonic-gate 			mutex_exit(&lp->l_mutex);
23707c478bd9Sstevel@tonic-gate 			return (scsa1394_cmd_fake_inquiry(sp, cmd));
23717c478bd9Sstevel@tonic-gate 		}
23727c478bd9Sstevel@tonic-gate 		break;
23737c478bd9Sstevel@tonic-gate 	case SCMD_MODE_SENSE:
23747c478bd9Sstevel@tonic-gate 		if (!lp->l_mode_sense_fake) {
23757c478bd9Sstevel@tonic-gate 			ret = DDI_FAILURE;
23767c478bd9Sstevel@tonic-gate 		} else {
23777c478bd9Sstevel@tonic-gate 			mutex_exit(&lp->l_mutex);
23787c478bd9Sstevel@tonic-gate 			return (scsa1394_cmd_fake_mode_sense(sp, cmd));
23797c478bd9Sstevel@tonic-gate 		}
23800ae3c1c1SToomas Soome 		break;
23817c478bd9Sstevel@tonic-gate 	default:
23827c478bd9Sstevel@tonic-gate 		ret = DDI_FAILURE;
23837c478bd9Sstevel@tonic-gate 	}
23847c478bd9Sstevel@tonic-gate 
23857c478bd9Sstevel@tonic-gate 	mutex_exit(&lp->l_mutex);
23867c478bd9Sstevel@tonic-gate 
23877c478bd9Sstevel@tonic-gate 	if (ret != DDI_SUCCESS) {
23887c478bd9Sstevel@tonic-gate 		return (ret);
23897c478bd9Sstevel@tonic-gate 	}
23907c478bd9Sstevel@tonic-gate 
23917c478bd9Sstevel@tonic-gate 	ASSERT(*(pkt->pkt_scbp) == STATUS_GOOD);
23927c478bd9Sstevel@tonic-gate 	ASSERT(pkt->pkt_reason == CMD_CMPLT);
23937c478bd9Sstevel@tonic-gate 	pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET | STATE_SENT_CMD |
23947c478bd9Sstevel@tonic-gate 	    STATE_XFERRED_DATA | STATE_GOT_STATUS);
23957c478bd9Sstevel@tonic-gate 
23967c478bd9Sstevel@tonic-gate 	if (pkt->pkt_comp) {
23977c478bd9Sstevel@tonic-gate 		(*pkt->pkt_comp)(pkt);
23987c478bd9Sstevel@tonic-gate 	}
23997c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
24007c478bd9Sstevel@tonic-gate }
24017c478bd9Sstevel@tonic-gate 
24027c478bd9Sstevel@tonic-gate /*
24037c478bd9Sstevel@tonic-gate  * Returns DDI_SUCCESS if next xfer setup successfully, DDI_FAILURE otherwise.
24047c478bd9Sstevel@tonic-gate  */
24057c478bd9Sstevel@tonic-gate static int
scsa1394_cmd_setup_next_xfer(scsa1394_lun_t * lp,scsa1394_cmd_t * cmd)24067c478bd9Sstevel@tonic-gate scsa1394_cmd_setup_next_xfer(scsa1394_lun_t *lp, scsa1394_cmd_t *cmd)
24077c478bd9Sstevel@tonic-gate {
24087c478bd9Sstevel@tonic-gate 	struct scsi_pkt		*pkt = CMD2PKT(cmd);
24097c478bd9Sstevel@tonic-gate 
24107c478bd9Sstevel@tonic-gate 	ASSERT(cmd->sc_flags & SCSA1394_CMD_SYMBIOS_BREAKUP);
24117c478bd9Sstevel@tonic-gate 
24127c478bd9Sstevel@tonic-gate 	cmd->sc_resid_blks -= cmd->sc_xfer_blks;
24137c478bd9Sstevel@tonic-gate 	if (cmd->sc_resid_blks <= 0) {
24147c478bd9Sstevel@tonic-gate 		pkt->pkt_resid = 0;
24157c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
24167c478bd9Sstevel@tonic-gate 	}
24177c478bd9Sstevel@tonic-gate 
24187c478bd9Sstevel@tonic-gate 	scsa1394_cmd_adjust_cdb(lp, cmd);
24197c478bd9Sstevel@tonic-gate 
24207c478bd9Sstevel@tonic-gate 	scsa1394_sbp2_seg2pt(lp, cmd);
24217c478bd9Sstevel@tonic-gate 
24227c478bd9Sstevel@tonic-gate 	scsa1394_sbp2_cmd2orb(lp, cmd);
24237c478bd9Sstevel@tonic-gate 
24247c478bd9Sstevel@tonic-gate 	if (scsa1394_sbp2_start(lp, cmd) != TRAN_ACCEPT) {
24257c478bd9Sstevel@tonic-gate 		pkt->pkt_resid = cmd->sc_resid_blks * cmd->sc_blk_size;
24267c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
24277c478bd9Sstevel@tonic-gate 	}
24287c478bd9Sstevel@tonic-gate 
24297c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
24307c478bd9Sstevel@tonic-gate }
24317c478bd9Sstevel@tonic-gate 
24327c478bd9Sstevel@tonic-gate /*
24337c478bd9Sstevel@tonic-gate  * new lba = current lba + previous xfer len
24347c478bd9Sstevel@tonic-gate  */
24357c478bd9Sstevel@tonic-gate /*ARGSUSED*/
24367c478bd9Sstevel@tonic-gate static void
scsa1394_cmd_adjust_cdb(scsa1394_lun_t * lp,scsa1394_cmd_t * cmd)24377c478bd9Sstevel@tonic-gate scsa1394_cmd_adjust_cdb(scsa1394_lun_t *lp, scsa1394_cmd_t *cmd)
24387c478bd9Sstevel@tonic-gate {
24397c478bd9Sstevel@tonic-gate 	int		len;
24407c478bd9Sstevel@tonic-gate 
24417c478bd9Sstevel@tonic-gate 	ASSERT(cmd->sc_flags & SCSA1394_CMD_SYMBIOS_BREAKUP);
24427c478bd9Sstevel@tonic-gate 
24437c478bd9Sstevel@tonic-gate 	cmd->sc_lba += cmd->sc_xfer_blks;
24447c478bd9Sstevel@tonic-gate 	len = cmd->sc_resid_blks;
24457c478bd9Sstevel@tonic-gate 
24467c478bd9Sstevel@tonic-gate 	/* limit xfer length for Symbios workaround */
24477c478bd9Sstevel@tonic-gate 	if (len * cmd->sc_blk_size > scsa1394_symbios_size_max) {
24487c478bd9Sstevel@tonic-gate 		len = scsa1394_symbios_size_max / cmd->sc_blk_size;
24497c478bd9Sstevel@tonic-gate 	}
24507c478bd9Sstevel@tonic-gate 
24517c478bd9Sstevel@tonic-gate 	switch (cmd->sc_cdb[0]) {
24527c478bd9Sstevel@tonic-gate 	case SCMD_READ_CD:
24537c478bd9Sstevel@tonic-gate 		scsa1394_cmd_fill_read_cd_cdb_len(cmd, len);
24547c478bd9Sstevel@tonic-gate 		break;
24557c478bd9Sstevel@tonic-gate 	case SCMD_WRITE_G5:
24567c478bd9Sstevel@tonic-gate 	case SCMD_READ_G5:
24577c478bd9Sstevel@tonic-gate 		scsa1394_cmd_fill_12byte_cdb_len(cmd, len);
24587c478bd9Sstevel@tonic-gate 		break;
24597c478bd9Sstevel@tonic-gate 	case SCMD_WRITE_G1:
24607c478bd9Sstevel@tonic-gate 	case SCMD_WRITE_LONG:
24617c478bd9Sstevel@tonic-gate 	default:
24627c478bd9Sstevel@tonic-gate 		scsa1394_cmd_fill_cdb_len(cmd, len);
24637c478bd9Sstevel@tonic-gate 	}
24647c478bd9Sstevel@tonic-gate 
24657c478bd9Sstevel@tonic-gate 	scsa1394_cmd_fill_cdb_lba(cmd, cmd->sc_lba);
24667c478bd9Sstevel@tonic-gate 
24677c478bd9Sstevel@tonic-gate 	cmd->sc_xfer_blks = len;
24687c478bd9Sstevel@tonic-gate 	cmd->sc_xfer_bytes = len * cmd->sc_blk_size;
24697c478bd9Sstevel@tonic-gate }
24707c478bd9Sstevel@tonic-gate 
24717c478bd9Sstevel@tonic-gate void
scsa1394_cmd_status_proc(scsa1394_lun_t * lp,scsa1394_cmd_t * cmd)24727c478bd9Sstevel@tonic-gate scsa1394_cmd_status_proc(scsa1394_lun_t *lp, scsa1394_cmd_t *cmd)
24737c478bd9Sstevel@tonic-gate {
24747c478bd9Sstevel@tonic-gate 	struct scsi_pkt		*pkt = CMD2PKT(cmd);
24757c478bd9Sstevel@tonic-gate 
24767c478bd9Sstevel@tonic-gate 	/* next iteration of partial xfer? */
24777c478bd9Sstevel@tonic-gate 	if ((pkt->pkt_reason == CMD_CMPLT) &&
24787c478bd9Sstevel@tonic-gate 	    (cmd->sc_flags & SCSA1394_CMD_SYMBIOS_BREAKUP)) {
24797c478bd9Sstevel@tonic-gate 		if (scsa1394_cmd_setup_next_xfer(lp, cmd) == DDI_SUCCESS) {
24807c478bd9Sstevel@tonic-gate 			return;
24817c478bd9Sstevel@tonic-gate 		}
24827c478bd9Sstevel@tonic-gate 	}
24837c478bd9Sstevel@tonic-gate 	cmd->sc_flags &= ~SCSA1394_CMD_SYMBIOS_BREAKUP;
24847c478bd9Sstevel@tonic-gate 
24857c478bd9Sstevel@tonic-gate 	/* apply workarounds */
24867c478bd9Sstevel@tonic-gate 	if (pkt->pkt_reason == CMD_CMPLT) {
24877c478bd9Sstevel@tonic-gate 		scsa1394_cmd_status_wrka(lp, cmd);
24887c478bd9Sstevel@tonic-gate 	}
24897c478bd9Sstevel@tonic-gate 
24907c478bd9Sstevel@tonic-gate 	mutex_enter(&lp->l_mutex);
24917c478bd9Sstevel@tonic-gate 
24927c478bd9Sstevel@tonic-gate 	/* mode sense workaround */
24937c478bd9Sstevel@tonic-gate 	if (pkt->pkt_cdbp[0] == SCMD_MODE_SENSE) {
24947c478bd9Sstevel@tonic-gate 		if (pkt->pkt_reason == CMD_CMPLT) {
24957c478bd9Sstevel@tonic-gate 			lp->l_mode_sense_fail_cnt = 0;
24967c478bd9Sstevel@tonic-gate 		} else if (++lp->l_mode_sense_fail_cnt >=
24977c478bd9Sstevel@tonic-gate 		    scsa1394_mode_sense_fail_max) {
24987c478bd9Sstevel@tonic-gate 			lp->l_mode_sense_fake = B_TRUE;
24997c478bd9Sstevel@tonic-gate 		}
25007c478bd9Sstevel@tonic-gate 	} else {
25017c478bd9Sstevel@tonic-gate 		lp->l_mode_sense_fail_cnt = 0;
25027c478bd9Sstevel@tonic-gate 	}
25037c478bd9Sstevel@tonic-gate 
25047c478bd9Sstevel@tonic-gate 	mutex_exit(&lp->l_mutex);
25057c478bd9Sstevel@tonic-gate 
25067c478bd9Sstevel@tonic-gate 	if (pkt->pkt_comp) {
25077c478bd9Sstevel@tonic-gate 		(*pkt->pkt_comp)(pkt);
25087c478bd9Sstevel@tonic-gate 	}
25097c478bd9Sstevel@tonic-gate }
25107c478bd9Sstevel@tonic-gate 
25117c478bd9Sstevel@tonic-gate static void
scsa1394_cmd_status_wrka(scsa1394_lun_t * lp,scsa1394_cmd_t * cmd)25127c478bd9Sstevel@tonic-gate scsa1394_cmd_status_wrka(scsa1394_lun_t *lp, scsa1394_cmd_t *cmd)
25137c478bd9Sstevel@tonic-gate {
25147c478bd9Sstevel@tonic-gate 	struct scsi_pkt	*pkt = CMD2PKT(cmd);
25157c478bd9Sstevel@tonic-gate 
25167c478bd9Sstevel@tonic-gate 	mutex_enter(&lp->l_mutex);
25177c478bd9Sstevel@tonic-gate 
25187c478bd9Sstevel@tonic-gate 	switch (pkt->pkt_cdbp[0]) {
25197c478bd9Sstevel@tonic-gate 	case SCMD_INQUIRY: {
25207c478bd9Sstevel@tonic-gate 		struct scsi_inquiry *inq;
25217c478bd9Sstevel@tonic-gate 
25227c478bd9Sstevel@tonic-gate 		inq = (struct scsi_inquiry *)cmd->sc_bp->b_un.b_addr;
25237c478bd9Sstevel@tonic-gate 
25247c478bd9Sstevel@tonic-gate 		/* change dtype RBC to DIRECT, sd doesn't support RBC */
25257c478bd9Sstevel@tonic-gate 		lp->l_dtype_orig = inq->inq_dtype;
25267c478bd9Sstevel@tonic-gate 		if ((inq->inq_dtype == SCSA1394_DTYPE_RBC) &&
25277c478bd9Sstevel@tonic-gate 		    scsa1394_wrka_rbc2direct) {
25287c478bd9Sstevel@tonic-gate 			inq->inq_dtype = DTYPE_DIRECT;
25297c478bd9Sstevel@tonic-gate 		}
25307c478bd9Sstevel@tonic-gate 
25317c478bd9Sstevel@tonic-gate 		/* force RMB to 1 */
25327c478bd9Sstevel@tonic-gate 		lp->l_rmb_orig = inq->inq_rmb;
25330167b58cScg 		if (scsa1394_wrka_fake_rmb) {
25347c478bd9Sstevel@tonic-gate 			inq->inq_rmb = 1;
25357c478bd9Sstevel@tonic-gate 		}
25367c478bd9Sstevel@tonic-gate 		break;
25377c478bd9Sstevel@tonic-gate 	}
25387c478bd9Sstevel@tonic-gate 	case SCMD_READ_CAPACITY: {
25397c478bd9Sstevel@tonic-gate 		uint32_t	*capacity_buf;
25407c478bd9Sstevel@tonic-gate 
25417c478bd9Sstevel@tonic-gate 		capacity_buf = (uint32_t *)cmd->sc_bp->b_un.b_addr;
25427c478bd9Sstevel@tonic-gate 
25437c478bd9Sstevel@tonic-gate 		if (lp->l_dtype_orig != DTYPE_RODIRECT) {
25447c478bd9Sstevel@tonic-gate 			lp->l_lba_size = min(BE_32(capacity_buf[1]), DEV_BSIZE);
25457c478bd9Sstevel@tonic-gate 			if (lp->l_lba_size == 0) {
25467c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "zero LBA size reported, "
25477c478bd9Sstevel@tonic-gate 				    "possibly broken device");
25487c478bd9Sstevel@tonic-gate 				lp->l_lba_size = DEV_BSIZE;
25497c478bd9Sstevel@tonic-gate 			}
25507c478bd9Sstevel@tonic-gate 		} else {
25517c478bd9Sstevel@tonic-gate 			lp->l_lba_size = 2048;
25527c478bd9Sstevel@tonic-gate 		}
25537c478bd9Sstevel@tonic-gate 	}
25547c478bd9Sstevel@tonic-gate 	default:
25557c478bd9Sstevel@tonic-gate 		break;
25567c478bd9Sstevel@tonic-gate 	}
25577c478bd9Sstevel@tonic-gate 
25587c478bd9Sstevel@tonic-gate 	mutex_exit(&lp->l_mutex);
25597c478bd9Sstevel@tonic-gate }
25607c478bd9Sstevel@tonic-gate 
25617c478bd9Sstevel@tonic-gate /*
25627c478bd9Sstevel@tonic-gate  * --- thread management
25637c478bd9Sstevel@tonic-gate  *
25647c478bd9Sstevel@tonic-gate  * dispatch a thread
25657c478bd9Sstevel@tonic-gate  */
25667c478bd9Sstevel@tonic-gate int
scsa1394_thr_dispatch(scsa1394_thread_t * thr)25677c478bd9Sstevel@tonic-gate scsa1394_thr_dispatch(scsa1394_thread_t *thr)
25687c478bd9Sstevel@tonic-gate {
25697c478bd9Sstevel@tonic-gate 	scsa1394_lun_t		*lp = thr->thr_lun;
25707c478bd9Sstevel@tonic-gate 	scsa1394_state_t	*sp = lp->l_sp;
25717c478bd9Sstevel@tonic-gate 	int			ret;
25727c478bd9Sstevel@tonic-gate 
25737c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&lp->l_mutex));
25747c478bd9Sstevel@tonic-gate 	ASSERT(thr->thr_state == SCSA1394_THR_INIT);
25757c478bd9Sstevel@tonic-gate 
25767c478bd9Sstevel@tonic-gate 	thr->thr_state = SCSA1394_THR_RUN;
25777c478bd9Sstevel@tonic-gate 
25787c478bd9Sstevel@tonic-gate 	ret = ddi_taskq_dispatch(sp->s_taskq, thr->thr_func, thr->thr_arg,
25797c478bd9Sstevel@tonic-gate 	    KM_SLEEP);
25807c478bd9Sstevel@tonic-gate 	return (ret);
25817c478bd9Sstevel@tonic-gate }
25827c478bd9Sstevel@tonic-gate 
25837c478bd9Sstevel@tonic-gate /*
25847c478bd9Sstevel@tonic-gate  * cancel thread
25857c478bd9Sstevel@tonic-gate  */
25867c478bd9Sstevel@tonic-gate void
scsa1394_thr_cancel(scsa1394_thread_t * thr)25877c478bd9Sstevel@tonic-gate scsa1394_thr_cancel(scsa1394_thread_t *thr)
25887c478bd9Sstevel@tonic-gate {
25897c478bd9Sstevel@tonic-gate 	scsa1394_lun_t		*lp = thr->thr_lun;
25907c478bd9Sstevel@tonic-gate 
25917c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&lp->l_mutex));
25927c478bd9Sstevel@tonic-gate 
25937c478bd9Sstevel@tonic-gate 	thr->thr_req |= SCSA1394_THREQ_EXIT;
25947c478bd9Sstevel@tonic-gate 	cv_signal(&thr->thr_cv);
25957c478bd9Sstevel@tonic-gate 
25967c478bd9Sstevel@tonic-gate 	/* wait until the thread actually exits */
25977c478bd9Sstevel@tonic-gate 	do {
25987c478bd9Sstevel@tonic-gate 		if (cv_wait_sig(&thr->thr_cv, &lp->l_mutex) == 0) {
25997c478bd9Sstevel@tonic-gate 			break;
26007c478bd9Sstevel@tonic-gate 		}
26017c478bd9Sstevel@tonic-gate 	} while (thr->thr_state != SCSA1394_THR_EXIT);
26027c478bd9Sstevel@tonic-gate }
26037c478bd9Sstevel@tonic-gate 
26047c478bd9Sstevel@tonic-gate /*
26057c478bd9Sstevel@tonic-gate  * wake thread
26067c478bd9Sstevel@tonic-gate  */
26077c478bd9Sstevel@tonic-gate void
scsa1394_thr_wake(scsa1394_thread_t * thr,int req)26087c478bd9Sstevel@tonic-gate scsa1394_thr_wake(scsa1394_thread_t *thr, int req)
26097c478bd9Sstevel@tonic-gate {
26107c478bd9Sstevel@tonic-gate 	scsa1394_lun_t		*lp = thr->thr_lun;
26117c478bd9Sstevel@tonic-gate 
26127c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&lp->l_mutex));
26137c478bd9Sstevel@tonic-gate 
26147c478bd9Sstevel@tonic-gate 	thr->thr_req |= req;
26157c478bd9Sstevel@tonic-gate 	cv_signal(&thr->thr_cv);
26167c478bd9Sstevel@tonic-gate }
26177c478bd9Sstevel@tonic-gate 
26187c478bd9Sstevel@tonic-gate void
scsa1394_thr_clear_req(scsa1394_thread_t * thr,int mask)26197c478bd9Sstevel@tonic-gate scsa1394_thr_clear_req(scsa1394_thread_t *thr, int mask)
26207c478bd9Sstevel@tonic-gate {
26217c478bd9Sstevel@tonic-gate 	scsa1394_lun_t		*lp = thr->thr_lun;
26227c478bd9Sstevel@tonic-gate 
26237c478bd9Sstevel@tonic-gate 	mutex_enter(&lp->l_mutex);
26247c478bd9Sstevel@tonic-gate 	thr->thr_req &= ~mask;
26257c478bd9Sstevel@tonic-gate 	mutex_exit(&lp->l_mutex);
26267c478bd9Sstevel@tonic-gate }
26277c478bd9Sstevel@tonic-gate 
26287c478bd9Sstevel@tonic-gate /*
26297c478bd9Sstevel@tonic-gate  *
26307c478bd9Sstevel@tonic-gate  * --- other routines
26317c478bd9Sstevel@tonic-gate  *
26327c478bd9Sstevel@tonic-gate  */
26337c478bd9Sstevel@tonic-gate static boolean_t
scsa1394_is_my_child(dev_info_t * dip)26347c478bd9Sstevel@tonic-gate scsa1394_is_my_child(dev_info_t *dip)
26357c478bd9Sstevel@tonic-gate {
26367c478bd9Sstevel@tonic-gate 	return ((dip != NULL) && (ddi_prop_exists(DDI_DEV_T_ANY, dip,
26377c478bd9Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "scsa1394") == 1));
26387c478bd9Sstevel@tonic-gate }
26397c478bd9Sstevel@tonic-gate 
26407c478bd9Sstevel@tonic-gate boolean_t
scsa1394_dev_is_online(scsa1394_state_t * sp)26417c478bd9Sstevel@tonic-gate scsa1394_dev_is_online(scsa1394_state_t *sp)
26427c478bd9Sstevel@tonic-gate {
26437c478bd9Sstevel@tonic-gate 	boolean_t	ret;
26447c478bd9Sstevel@tonic-gate 
26457c478bd9Sstevel@tonic-gate 	mutex_enter(&sp->s_mutex);
26467c478bd9Sstevel@tonic-gate 	ret = (sp->s_dev_state == SCSA1394_DEV_ONLINE);
26477c478bd9Sstevel@tonic-gate 	mutex_exit(&sp->s_mutex);
26487c478bd9Sstevel@tonic-gate 
26497c478bd9Sstevel@tonic-gate 	return (ret);
26507c478bd9Sstevel@tonic-gate }
26517c478bd9Sstevel@tonic-gate 
26527c478bd9Sstevel@tonic-gate static void *
scsa1394_kmem_realloc(void * old_buf,int old_size,int new_size,size_t elsize,int kf)26537c478bd9Sstevel@tonic-gate scsa1394_kmem_realloc(void *old_buf, int old_size, int new_size, size_t elsize,
26547c478bd9Sstevel@tonic-gate     int kf)
26557c478bd9Sstevel@tonic-gate {
26567c478bd9Sstevel@tonic-gate 	void	*new_buf;
26577c478bd9Sstevel@tonic-gate 
26587c478bd9Sstevel@tonic-gate 	new_buf = kmem_zalloc(new_size * elsize, kf);
26597c478bd9Sstevel@tonic-gate 
26607c478bd9Sstevel@tonic-gate 	if (old_size > 0) {
26617c478bd9Sstevel@tonic-gate 		if (new_buf != NULL) {
26627c478bd9Sstevel@tonic-gate 			bcopy(old_buf, new_buf, old_size * elsize);
26637c478bd9Sstevel@tonic-gate 		}
26647c478bd9Sstevel@tonic-gate 		kmem_free(old_buf, old_size * elsize);
26657c478bd9Sstevel@tonic-gate 	}
26667c478bd9Sstevel@tonic-gate 
26677c478bd9Sstevel@tonic-gate 	return (new_buf);
26687c478bd9Sstevel@tonic-gate }
2669