10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
51963Sap25164 * Common Development and Distribution License (the "License").
61963Sap25164 * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
228763SAlan.Perry@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate
270Sstevel@tonic-gate /*
280Sstevel@tonic-gate * 1394 mass storage HBA driver
290Sstevel@tonic-gate */
300Sstevel@tonic-gate
310Sstevel@tonic-gate #include <sys/param.h>
320Sstevel@tonic-gate #include <sys/errno.h>
330Sstevel@tonic-gate #include <sys/cred.h>
340Sstevel@tonic-gate #include <sys/conf.h>
350Sstevel@tonic-gate #include <sys/modctl.h>
360Sstevel@tonic-gate #include <sys/stat.h>
370Sstevel@tonic-gate #include <sys/byteorder.h>
380Sstevel@tonic-gate #include <sys/ddi.h>
390Sstevel@tonic-gate #include <sys/sunddi.h>
400Sstevel@tonic-gate
410Sstevel@tonic-gate #include <sys/1394/targets/scsa1394/impl.h>
420Sstevel@tonic-gate #include <sys/1394/targets/scsa1394/cmd.h>
430Sstevel@tonic-gate
440Sstevel@tonic-gate /* DDI/DKI entry points */
450Sstevel@tonic-gate static int scsa1394_attach(dev_info_t *, ddi_attach_cmd_t);
460Sstevel@tonic-gate static int scsa1394_detach(dev_info_t *, ddi_detach_cmd_t);
470Sstevel@tonic-gate static int scsa1394_power(dev_info_t *, int, int);
486881Sbharding static int scsa1394_cpr_suspend(dev_info_t *);
496881Sbharding static void scsa1394_cpr_resume(dev_info_t *);
500Sstevel@tonic-gate
510Sstevel@tonic-gate /* configuration routines */
520Sstevel@tonic-gate static void scsa1394_cleanup(scsa1394_state_t *, int);
530Sstevel@tonic-gate static int scsa1394_attach_1394(scsa1394_state_t *);
540Sstevel@tonic-gate static void scsa1394_detach_1394(scsa1394_state_t *);
550Sstevel@tonic-gate static int scsa1394_attach_threads(scsa1394_state_t *);
560Sstevel@tonic-gate static void scsa1394_detach_threads(scsa1394_state_t *);
570Sstevel@tonic-gate static int scsa1394_attach_scsa(scsa1394_state_t *);
580Sstevel@tonic-gate static void scsa1394_detach_scsa(scsa1394_state_t *);
590Sstevel@tonic-gate static int scsa1394_create_cmd_cache(scsa1394_state_t *);
600Sstevel@tonic-gate static void scsa1394_destroy_cmd_cache(scsa1394_state_t *);
610Sstevel@tonic-gate static int scsa1394_add_events(scsa1394_state_t *);
620Sstevel@tonic-gate static void scsa1394_remove_events(scsa1394_state_t *);
630Sstevel@tonic-gate
640Sstevel@tonic-gate /* device configuration */
650Sstevel@tonic-gate static int scsa1394_scsi_bus_config(dev_info_t *, uint_t,
660Sstevel@tonic-gate ddi_bus_config_op_t, void *, dev_info_t **);
670Sstevel@tonic-gate static int scsa1394_scsi_bus_unconfig(dev_info_t *, uint_t,
680Sstevel@tonic-gate ddi_bus_config_op_t, void *);
690Sstevel@tonic-gate static void scsa1394_create_children(scsa1394_state_t *);
700Sstevel@tonic-gate static void scsa1394_bus_reset(dev_info_t *, ddi_eventcookie_t, void *,
710Sstevel@tonic-gate void *);
720Sstevel@tonic-gate static void scsa1394_disconnect(dev_info_t *, ddi_eventcookie_t, void *,
730Sstevel@tonic-gate void *);
740Sstevel@tonic-gate static void scsa1394_reconnect(dev_info_t *, ddi_eventcookie_t, void *,
750Sstevel@tonic-gate void *);
760Sstevel@tonic-gate
770Sstevel@tonic-gate /* SCSA HBA entry points */
780Sstevel@tonic-gate static int scsa1394_scsi_tgt_init(dev_info_t *, dev_info_t *,
790Sstevel@tonic-gate scsi_hba_tran_t *, struct scsi_device *);
800Sstevel@tonic-gate static void scsa1394_scsi_tgt_free(dev_info_t *, dev_info_t *,
810Sstevel@tonic-gate scsi_hba_tran_t *, struct scsi_device *);
820Sstevel@tonic-gate static int scsa1394_scsi_tgt_probe(struct scsi_device *, int (*)());
830Sstevel@tonic-gate static int scsa1394_probe_g0_nodata(struct scsi_device *, int (*)(),
840Sstevel@tonic-gate uchar_t, uint_t, uint_t);
850Sstevel@tonic-gate static int scsa1394_probe_tran(struct scsi_pkt *);
860Sstevel@tonic-gate static struct scsi_pkt *scsa1394_scsi_init_pkt(struct scsi_address *,
870Sstevel@tonic-gate struct scsi_pkt *, struct buf *, int, int, int, int,
880Sstevel@tonic-gate int (*)(), caddr_t arg);
890Sstevel@tonic-gate static void scsa1394_scsi_destroy_pkt(struct scsi_address *,
900Sstevel@tonic-gate struct scsi_pkt *);
910Sstevel@tonic-gate static int scsa1394_scsi_start(struct scsi_address *, struct scsi_pkt *);
920Sstevel@tonic-gate static int scsa1394_scsi_abort(struct scsi_address *, struct scsi_pkt *);
930Sstevel@tonic-gate static int scsa1394_scsi_reset(struct scsi_address *, int);
940Sstevel@tonic-gate static int scsa1394_scsi_getcap(struct scsi_address *, char *, int);
950Sstevel@tonic-gate static int scsa1394_scsi_setcap(struct scsi_address *, char *, int, int);
960Sstevel@tonic-gate static void scsa1394_scsi_dmafree(struct scsi_address *, struct scsi_pkt *);
970Sstevel@tonic-gate static void scsa1394_scsi_sync_pkt(struct scsi_address *,
980Sstevel@tonic-gate struct scsi_pkt *);
990Sstevel@tonic-gate
1000Sstevel@tonic-gate /* pkt resource allocation routines */
1010Sstevel@tonic-gate static int scsa1394_cmd_cache_constructor(void *, void *, int);
1020Sstevel@tonic-gate static void scsa1394_cmd_cache_destructor(void *, void *);
1030Sstevel@tonic-gate static int scsa1394_cmd_ext_alloc(scsa1394_state_t *, scsa1394_cmd_t *,
1040Sstevel@tonic-gate int);
1050Sstevel@tonic-gate static void scsa1394_cmd_ext_free(scsa1394_state_t *, scsa1394_cmd_t *);
1060Sstevel@tonic-gate static int scsa1394_cmd_cdb_dma_alloc(scsa1394_state_t *, scsa1394_cmd_t *,
1070Sstevel@tonic-gate int, int (*)(), caddr_t);
1080Sstevel@tonic-gate static void scsa1394_cmd_cdb_dma_free(scsa1394_state_t *, scsa1394_cmd_t *);
1090Sstevel@tonic-gate static int scsa1394_cmd_buf_dma_alloc(scsa1394_state_t *, scsa1394_cmd_t *,
1100Sstevel@tonic-gate int, int (*)(), caddr_t, struct buf *);
1110Sstevel@tonic-gate static void scsa1394_cmd_buf_dma_free(scsa1394_state_t *, scsa1394_cmd_t *);
1120Sstevel@tonic-gate static int scsa1394_cmd_dmac2seg(scsa1394_state_t *, scsa1394_cmd_t *,
1130Sstevel@tonic-gate ddi_dma_cookie_t *, uint_t, int);
1140Sstevel@tonic-gate static void scsa1394_cmd_seg_free(scsa1394_state_t *, scsa1394_cmd_t *);
1150Sstevel@tonic-gate static int scsa1394_cmd_pt_dma_alloc(scsa1394_state_t *, scsa1394_cmd_t *,
1160Sstevel@tonic-gate int (*)(), caddr_t, int);
1170Sstevel@tonic-gate static void scsa1394_cmd_pt_dma_free(scsa1394_state_t *, scsa1394_cmd_t *);
1180Sstevel@tonic-gate static int scsa1394_cmd_buf_addr_alloc(scsa1394_state_t *,
1190Sstevel@tonic-gate scsa1394_cmd_t *);
1200Sstevel@tonic-gate static void scsa1394_cmd_buf_addr_free(scsa1394_state_t *,
1210Sstevel@tonic-gate scsa1394_cmd_t *);
1220Sstevel@tonic-gate static int scsa1394_cmd_buf_dma_move(scsa1394_state_t *, scsa1394_cmd_t *);
1230Sstevel@tonic-gate
1240Sstevel@tonic-gate
1250Sstevel@tonic-gate /* pkt and data transfer routines */
1260Sstevel@tonic-gate static void scsa1394_prepare_pkt(scsa1394_state_t *, struct scsi_pkt *);
1270Sstevel@tonic-gate static void scsa1394_cmd_fill_cdb(scsa1394_lun_t *, scsa1394_cmd_t *);
1280Sstevel@tonic-gate static void scsa1394_cmd_fill_cdb_rbc(scsa1394_lun_t *, scsa1394_cmd_t *);
1290Sstevel@tonic-gate static void scsa1394_cmd_fill_cdb_other(scsa1394_lun_t *, scsa1394_cmd_t *);
1300Sstevel@tonic-gate static void scsa1394_cmd_fill_cdb_len(scsa1394_cmd_t *, int);
1310Sstevel@tonic-gate static void scsa1394_cmd_fill_cdb_lba(scsa1394_cmd_t *, int);
1320Sstevel@tonic-gate static void scsa1394_cmd_fill_12byte_cdb_len(scsa1394_cmd_t *, int);
1330Sstevel@tonic-gate static void scsa1394_cmd_fill_read_cd_cdb_len(scsa1394_cmd_t *, int);
1340Sstevel@tonic-gate static int scsa1394_cmd_read_cd_blk_size(uchar_t);
1350Sstevel@tonic-gate static int scsa1394_cmd_fake_mode_sense(scsa1394_state_t *,
1360Sstevel@tonic-gate scsa1394_cmd_t *);
1370Sstevel@tonic-gate static int scsa1394_cmd_fake_inquiry(scsa1394_state_t *, scsa1394_cmd_t *);
1380Sstevel@tonic-gate static int scsa1394_cmd_fake_comp(scsa1394_state_t *, scsa1394_cmd_t *);
1390Sstevel@tonic-gate static int scsa1394_cmd_setup_next_xfer(scsa1394_lun_t *,
1400Sstevel@tonic-gate scsa1394_cmd_t *);
1410Sstevel@tonic-gate static void scsa1394_cmd_adjust_cdb(scsa1394_lun_t *, scsa1394_cmd_t *);
1420Sstevel@tonic-gate static void scsa1394_cmd_status_wrka(scsa1394_lun_t *, scsa1394_cmd_t *);
1430Sstevel@tonic-gate
1440Sstevel@tonic-gate /* other routines */
1450Sstevel@tonic-gate static boolean_t scsa1394_is_my_child(dev_info_t *);
1460Sstevel@tonic-gate static void * scsa1394_kmem_realloc(void *, int, int, size_t, int);
1470Sstevel@tonic-gate
1480Sstevel@tonic-gate static void *scsa1394_statep;
1490Sstevel@tonic-gate #define SCSA1394_INST2STATE(inst) (ddi_get_soft_state(scsa1394_statep, inst))
1500Sstevel@tonic-gate
1510Sstevel@tonic-gate static struct cb_ops scsa1394_cb_ops = {
1520Sstevel@tonic-gate nodev, /* open */
1530Sstevel@tonic-gate nodev, /* close */
1540Sstevel@tonic-gate nodev, /* strategy */
1550Sstevel@tonic-gate nodev, /* print */
1560Sstevel@tonic-gate nodev, /* dump */
1570Sstevel@tonic-gate nodev, /* read */
1580Sstevel@tonic-gate nodev, /* write */
1590Sstevel@tonic-gate NULL, /* ioctl */
1600Sstevel@tonic-gate nodev, /* devmap */
1610Sstevel@tonic-gate nodev, /* mmap */
1620Sstevel@tonic-gate nodev, /* segmap */
1630Sstevel@tonic-gate nochpoll, /* poll */
1640Sstevel@tonic-gate ddi_prop_op, /* prop_op */
1650Sstevel@tonic-gate NULL, /* stream */
1660Sstevel@tonic-gate D_MP, /* cb_flag */
1676881Sbharding CB_REV, /* rev */
1680Sstevel@tonic-gate nodev, /* aread */
1690Sstevel@tonic-gate nodev /* awrite */
1700Sstevel@tonic-gate };
1710Sstevel@tonic-gate
1720Sstevel@tonic-gate static struct dev_ops scsa1394_ops = {
1730Sstevel@tonic-gate DEVO_REV, /* devo_rev, */
1740Sstevel@tonic-gate 0, /* refcnt */
1750Sstevel@tonic-gate ddi_no_info, /* info */
1760Sstevel@tonic-gate nulldev, /* identify */
1770Sstevel@tonic-gate nulldev, /* probe */
1780Sstevel@tonic-gate scsa1394_attach, /* attach */
1790Sstevel@tonic-gate scsa1394_detach, /* detach */
1800Sstevel@tonic-gate nodev, /* reset */
1810Sstevel@tonic-gate &scsa1394_cb_ops, /* driver operations */
1820Sstevel@tonic-gate NULL, /* bus operations */
1837656SSherry.Moore@Sun.COM scsa1394_power, /* power */
1847656SSherry.Moore@Sun.COM ddi_quiesce_not_supported, /* devo_quiesce */
1850Sstevel@tonic-gate };
1860Sstevel@tonic-gate
1870Sstevel@tonic-gate static struct modldrv scsa1394_modldrv = {
1880Sstevel@tonic-gate &mod_driverops, /* module type */
1896881Sbharding "1394 Mass Storage HBA Driver", /* name of the module */
1900Sstevel@tonic-gate &scsa1394_ops, /* driver ops */
1910Sstevel@tonic-gate };
1920Sstevel@tonic-gate
1930Sstevel@tonic-gate static struct modlinkage scsa1394_modlinkage = {
1940Sstevel@tonic-gate MODREV_1, (void *)&scsa1394_modldrv, NULL
1950Sstevel@tonic-gate };
1960Sstevel@tonic-gate
1970Sstevel@tonic-gate /* tunables */
1980Sstevel@tonic-gate int scsa1394_bus_config_debug = 0;
1990Sstevel@tonic-gate int scsa1394_start_stop_fail_max = SCSA1394_START_STOP_FAIL_MAX;
2000Sstevel@tonic-gate int scsa1394_mode_sense_fail_max = SCSA1394_MODE_SENSE_FAIL_MAX;
2010Sstevel@tonic-gate int scsa1394_start_stop_timeout_max = SCSA1394_START_STOP_TIMEOUT_MAX;
2020Sstevel@tonic-gate
2030Sstevel@tonic-gate /* workarounds */
2040Sstevel@tonic-gate int scsa1394_wrka_rbc2direct = 1;
2051415Scg149915 int scsa1394_wrka_fake_rmb = 0;
2060Sstevel@tonic-gate int scsa1394_wrka_fake_prin = 1;
2070Sstevel@tonic-gate
2080Sstevel@tonic-gate int scsa1394_wrka_symbios = 1;
2090Sstevel@tonic-gate int scsa1394_symbios_page_size = 4 * 1024; /* must be <= _pagesize */
2100Sstevel@tonic-gate int scsa1394_symbios_size_max = 512 * 248; /* multiple of page size */
2110Sstevel@tonic-gate
2120Sstevel@tonic-gate /*
2130Sstevel@tonic-gate *
2140Sstevel@tonic-gate * --- DDI/DKI entry points
2150Sstevel@tonic-gate *
2160Sstevel@tonic-gate */
2170Sstevel@tonic-gate int
_init(void)2180Sstevel@tonic-gate _init(void)
2190Sstevel@tonic-gate {
2200Sstevel@tonic-gate int ret;
2210Sstevel@tonic-gate
2220Sstevel@tonic-gate if (((ret = ddi_soft_state_init(&scsa1394_statep,
2230Sstevel@tonic-gate sizeof (scsa1394_state_t), 1)) != 0)) {
2240Sstevel@tonic-gate return (ret);
2250Sstevel@tonic-gate }
2260Sstevel@tonic-gate
2270Sstevel@tonic-gate if ((ret = scsi_hba_init(&scsa1394_modlinkage)) != 0) {
2280Sstevel@tonic-gate ddi_soft_state_fini(&scsa1394_statep);
2290Sstevel@tonic-gate return (ret);
2300Sstevel@tonic-gate }
2310Sstevel@tonic-gate
2320Sstevel@tonic-gate if ((ret = mod_install(&scsa1394_modlinkage)) != 0) {
2330Sstevel@tonic-gate scsi_hba_fini(&scsa1394_modlinkage);
2340Sstevel@tonic-gate ddi_soft_state_fini(&scsa1394_statep);
2350Sstevel@tonic-gate return (ret);
2360Sstevel@tonic-gate }
2370Sstevel@tonic-gate
2380Sstevel@tonic-gate return (ret);
2390Sstevel@tonic-gate }
2400Sstevel@tonic-gate
2410Sstevel@tonic-gate int
_fini(void)2420Sstevel@tonic-gate _fini(void)
2430Sstevel@tonic-gate {
2440Sstevel@tonic-gate int ret;
2450Sstevel@tonic-gate
2460Sstevel@tonic-gate if ((ret = mod_remove(&scsa1394_modlinkage)) == 0) {
2470Sstevel@tonic-gate scsi_hba_fini(&scsa1394_modlinkage);
2480Sstevel@tonic-gate ddi_soft_state_fini(&scsa1394_statep);
2490Sstevel@tonic-gate }
2500Sstevel@tonic-gate
2510Sstevel@tonic-gate return (ret);
2520Sstevel@tonic-gate }
2530Sstevel@tonic-gate
2540Sstevel@tonic-gate int
_info(struct modinfo * modinfop)2550Sstevel@tonic-gate _info(struct modinfo *modinfop)
2560Sstevel@tonic-gate {
2570Sstevel@tonic-gate return (mod_info(&scsa1394_modlinkage, modinfop));
2580Sstevel@tonic-gate }
2590Sstevel@tonic-gate
2600Sstevel@tonic-gate static int
scsa1394_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)2610Sstevel@tonic-gate scsa1394_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2620Sstevel@tonic-gate {
2630Sstevel@tonic-gate int instance = ddi_get_instance(dip);
2640Sstevel@tonic-gate scsa1394_state_t *sp;
2650Sstevel@tonic-gate
2660Sstevel@tonic-gate switch (cmd) {
2670Sstevel@tonic-gate case DDI_ATTACH:
2680Sstevel@tonic-gate break;
2690Sstevel@tonic-gate case DDI_RESUME:
2706881Sbharding scsa1394_cpr_resume(dip);
2710Sstevel@tonic-gate return (DDI_SUCCESS);
2720Sstevel@tonic-gate default:
2730Sstevel@tonic-gate return (DDI_FAILURE);
2740Sstevel@tonic-gate }
2750Sstevel@tonic-gate
2760Sstevel@tonic-gate if (ddi_soft_state_zalloc(scsa1394_statep, instance) != 0) {
2770Sstevel@tonic-gate return (DDI_FAILURE);
2780Sstevel@tonic-gate }
2790Sstevel@tonic-gate sp = SCSA1394_INST2STATE(instance);
2800Sstevel@tonic-gate
2810Sstevel@tonic-gate #ifndef __lock_lint
2820Sstevel@tonic-gate sp->s_dip = dip;
2830Sstevel@tonic-gate sp->s_instance = instance;
2840Sstevel@tonic-gate #endif
2850Sstevel@tonic-gate mutex_init(&sp->s_mutex, NULL, MUTEX_DRIVER,
2860Sstevel@tonic-gate sp->s_attachinfo.iblock_cookie);
2870Sstevel@tonic-gate cv_init(&sp->s_event_cv, NULL, CV_DRIVER, NULL);
2880Sstevel@tonic-gate
2890Sstevel@tonic-gate if (scsa1394_attach_1394(sp) != DDI_SUCCESS) {
2900Sstevel@tonic-gate scsa1394_cleanup(sp, 1);
2910Sstevel@tonic-gate return (DDI_FAILURE);
2920Sstevel@tonic-gate }
2930Sstevel@tonic-gate
2940Sstevel@tonic-gate if (scsa1394_sbp2_attach(sp) != DDI_SUCCESS) {
2950Sstevel@tonic-gate scsa1394_cleanup(sp, 2);
2960Sstevel@tonic-gate return (DDI_FAILURE);
2970Sstevel@tonic-gate }
2980Sstevel@tonic-gate
2990Sstevel@tonic-gate if (scsa1394_attach_threads(sp) != DDI_SUCCESS) {
3000Sstevel@tonic-gate scsa1394_cleanup(sp, 3);
3010Sstevel@tonic-gate return (DDI_FAILURE);
3020Sstevel@tonic-gate }
3030Sstevel@tonic-gate
3040Sstevel@tonic-gate if (scsa1394_attach_scsa(sp) != DDI_SUCCESS) {
3050Sstevel@tonic-gate scsa1394_cleanup(sp, 4);
3060Sstevel@tonic-gate return (DDI_FAILURE);
3070Sstevel@tonic-gate }
3080Sstevel@tonic-gate
3090Sstevel@tonic-gate if (scsa1394_create_cmd_cache(sp) != DDI_SUCCESS) {
3100Sstevel@tonic-gate scsa1394_cleanup(sp, 5);
3110Sstevel@tonic-gate return (DDI_FAILURE);
3120Sstevel@tonic-gate }
3130Sstevel@tonic-gate
3140Sstevel@tonic-gate if (scsa1394_add_events(sp) != DDI_SUCCESS) {
3150Sstevel@tonic-gate scsa1394_cleanup(sp, 6);
3160Sstevel@tonic-gate return (DDI_FAILURE);
3170Sstevel@tonic-gate }
3180Sstevel@tonic-gate
3196881Sbharding /* prevent async PM changes until we are done */
3206881Sbharding (void) pm_busy_component(dip, 0);
3216881Sbharding
3226881Sbharding /* Set power to full on */
3236881Sbharding (void) pm_raise_power(dip, 0, PM_LEVEL_D0);
3246881Sbharding
3256881Sbharding /* we are done */
3266881Sbharding (void) pm_idle_component(dip, 0);
3276881Sbharding
3280Sstevel@tonic-gate #ifndef __lock_lint
3290Sstevel@tonic-gate sp->s_dev_state = SCSA1394_DEV_ONLINE;
3300Sstevel@tonic-gate #endif
3310Sstevel@tonic-gate
3320Sstevel@tonic-gate ddi_report_dev(dip);
3330Sstevel@tonic-gate
3340Sstevel@tonic-gate return (DDI_SUCCESS);
3350Sstevel@tonic-gate }
3360Sstevel@tonic-gate
3370Sstevel@tonic-gate static int
scsa1394_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)3380Sstevel@tonic-gate scsa1394_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
3390Sstevel@tonic-gate {
3400Sstevel@tonic-gate int instance = ddi_get_instance(dip);
3410Sstevel@tonic-gate scsa1394_state_t *sp;
3420Sstevel@tonic-gate
3430Sstevel@tonic-gate if ((sp = SCSA1394_INST2STATE(instance)) == NULL) {
3440Sstevel@tonic-gate return (DDI_FAILURE);
3450Sstevel@tonic-gate }
3460Sstevel@tonic-gate
3470Sstevel@tonic-gate switch (cmd) {
3480Sstevel@tonic-gate case DDI_DETACH:
3496881Sbharding /* Cycle power state to off and idle where done/gone */
3506881Sbharding (void) pm_lower_power(dip, 0, PM_LEVEL_D3);
3516881Sbharding
3520Sstevel@tonic-gate scsa1394_cleanup(sp, SCSA1394_CLEANUP_LEVEL_MAX);
3530Sstevel@tonic-gate return (DDI_SUCCESS);
3540Sstevel@tonic-gate case DDI_SUSPEND:
3556881Sbharding return (scsa1394_cpr_suspend(dip));
3560Sstevel@tonic-gate default:
3570Sstevel@tonic-gate return (DDI_FAILURE);
3580Sstevel@tonic-gate }
3590Sstevel@tonic-gate }
3600Sstevel@tonic-gate
3610Sstevel@tonic-gate /*ARGSUSED*/
3620Sstevel@tonic-gate static int
scsa1394_power(dev_info_t * dip,int comp,int level)3630Sstevel@tonic-gate scsa1394_power(dev_info_t *dip, int comp, int level)
3640Sstevel@tonic-gate {
3650Sstevel@tonic-gate return (DDI_SUCCESS);
3660Sstevel@tonic-gate }
3670Sstevel@tonic-gate
3680Sstevel@tonic-gate /*
3696881Sbharding * scsa1394_cpr_suspend
3706881Sbharding * determine if the device's state can be changed to SUSPENDED
3716881Sbharding */
3726881Sbharding /* ARGSUSED */
3736881Sbharding static int
scsa1394_cpr_suspend(dev_info_t * dip)3746881Sbharding scsa1394_cpr_suspend(dev_info_t *dip)
3756881Sbharding {
3766881Sbharding int instance = ddi_get_instance(dip);
3776881Sbharding scsa1394_state_t *sp;
3786881Sbharding int rval = DDI_FAILURE;
3796881Sbharding
3806881Sbharding sp = SCSA1394_INST2STATE(instance);
3816881Sbharding
3826881Sbharding ASSERT(sp != NULL);
3836881Sbharding
3846881Sbharding
3856881Sbharding mutex_enter(&sp->s_mutex);
3866881Sbharding switch (sp->s_dev_state) {
3876881Sbharding case SCSA1394_DEV_ONLINE:
3886881Sbharding case SCSA1394_DEV_PWRED_DOWN:
3896881Sbharding case SCSA1394_DEV_DISCONNECTED:
3906881Sbharding sp->s_dev_state = SCSA1394_DEV_SUSPENDED;
3916881Sbharding
3926881Sbharding /* Power down and make device idle */
3936881Sbharding (void) pm_lower_power(dip, 0, PM_LEVEL_D3);
3946881Sbharding
3956881Sbharding rval = DDI_SUCCESS;
3966881Sbharding break;
3976881Sbharding case SCSA1394_DEV_SUSPENDED:
3986881Sbharding default:
3996881Sbharding if (scsa1394_bus_config_debug)
4006881Sbharding cmn_err(CE_WARN,
4016881Sbharding "scsa1304_cpr_suspend: Illegal dev state: %d",
4026881Sbharding sp->s_dev_state);
4036881Sbharding
4046881Sbharding rval = DDI_SUCCESS;
4056881Sbharding break;
4066881Sbharding }
4076881Sbharding mutex_exit(&sp->s_mutex);
4086881Sbharding
4096881Sbharding return (rval);
4106881Sbharding }
4116881Sbharding
4126881Sbharding /*
4136881Sbharding * scsa2usb_cpr_resume:
4146881Sbharding * restore device's state
4156881Sbharding */
4166881Sbharding static void
scsa1394_cpr_resume(dev_info_t * dip)4176881Sbharding scsa1394_cpr_resume(dev_info_t *dip)
4186881Sbharding {
4196881Sbharding int instance = ddi_get_instance(dip);
4206881Sbharding scsa1394_state_t *sp;
4216881Sbharding int i;
4226881Sbharding scsa1394_lun_t *lp;
4236881Sbharding
4246881Sbharding sp = SCSA1394_INST2STATE(instance);
4256881Sbharding
4266881Sbharding ASSERT(sp != NULL);
4276881Sbharding
4286881Sbharding if (sp->s_dev_state != SCSA1394_DEV_SUSPENDED)
4296881Sbharding return;
4306881Sbharding
4316881Sbharding /*
4326881Sbharding * Go through each lun and reset it to force a reconnect.
4336881Sbharding */
4346881Sbharding for (i = 0; i < sp->s_nluns; i++) {
4356881Sbharding lp = &sp->s_lun[i];
4366881Sbharding if (lp->l_ses != NULL) { /* Are we loged in? */
4376881Sbharding scsa1394_sbp2_req_bus_reset(lp);
4386881Sbharding scsa1394_sbp2_req_reconnect(lp);
4396881Sbharding }
4406881Sbharding }
4416881Sbharding
4426881Sbharding /* we are down so let the power get managed */
4436881Sbharding (void) pm_idle_component(dip, 0);
4446881Sbharding }
4456881Sbharding
4466881Sbharding
4476881Sbharding
4486881Sbharding /*
4490Sstevel@tonic-gate *
4500Sstevel@tonic-gate * --- configuration routines
4510Sstevel@tonic-gate *
4520Sstevel@tonic-gate */
4530Sstevel@tonic-gate static void
scsa1394_cleanup(scsa1394_state_t * sp,int level)4540Sstevel@tonic-gate scsa1394_cleanup(scsa1394_state_t *sp, int level)
4550Sstevel@tonic-gate {
4560Sstevel@tonic-gate ASSERT((level > 0) && (level <= SCSA1394_CLEANUP_LEVEL_MAX));
4570Sstevel@tonic-gate
4580Sstevel@tonic-gate switch (level) {
4590Sstevel@tonic-gate default:
4600Sstevel@tonic-gate scsa1394_remove_events(sp);
4610Sstevel@tonic-gate /* FALLTHRU */
4620Sstevel@tonic-gate case 6:
4630Sstevel@tonic-gate scsa1394_detach_scsa(sp);
4640Sstevel@tonic-gate /* FALLTHRU */
4650Sstevel@tonic-gate case 5:
4660Sstevel@tonic-gate scsa1394_destroy_cmd_cache(sp);
4670Sstevel@tonic-gate /* FALLTHRU */
4680Sstevel@tonic-gate case 4:
4690Sstevel@tonic-gate scsa1394_detach_threads(sp);
4700Sstevel@tonic-gate /* FALLTHRU */
4710Sstevel@tonic-gate case 3:
4720Sstevel@tonic-gate scsa1394_sbp2_detach(sp);
4730Sstevel@tonic-gate /* FALLTHRU */
4740Sstevel@tonic-gate case 2:
4750Sstevel@tonic-gate scsa1394_detach_1394(sp);
4760Sstevel@tonic-gate /* FALLTHRU */
4770Sstevel@tonic-gate case 1:
4780Sstevel@tonic-gate cv_destroy(&sp->s_event_cv);
4790Sstevel@tonic-gate mutex_destroy(&sp->s_mutex);
4800Sstevel@tonic-gate ddi_soft_state_free(scsa1394_statep, sp->s_instance);
4810Sstevel@tonic-gate }
4820Sstevel@tonic-gate }
4830Sstevel@tonic-gate
4840Sstevel@tonic-gate static int
scsa1394_attach_1394(scsa1394_state_t * sp)4850Sstevel@tonic-gate scsa1394_attach_1394(scsa1394_state_t *sp)
4860Sstevel@tonic-gate {
4870Sstevel@tonic-gate int ret;
4880Sstevel@tonic-gate
4890Sstevel@tonic-gate if ((ret = t1394_attach(sp->s_dip, T1394_VERSION_V1, 0,
4900Sstevel@tonic-gate &sp->s_attachinfo, &sp->s_t1394_hdl)) != DDI_SUCCESS) {
4910Sstevel@tonic-gate return (ret);
4920Sstevel@tonic-gate }
4930Sstevel@tonic-gate
4940Sstevel@tonic-gate /* DMA attributes for data buffers */
4950Sstevel@tonic-gate sp->s_buf_dma_attr = sp->s_attachinfo.dma_attr;
4960Sstevel@tonic-gate
4970Sstevel@tonic-gate /* DMA attributes for page tables */
4980Sstevel@tonic-gate sp->s_pt_dma_attr = sp->s_attachinfo.dma_attr;
4990Sstevel@tonic-gate sp->s_pt_dma_attr.dma_attr_sgllen = 1; /* pt must be contiguous */
5000Sstevel@tonic-gate
5010Sstevel@tonic-gate if ((ret = t1394_get_targetinfo(sp->s_t1394_hdl, SCSA1394_BUSGEN(sp), 0,
5020Sstevel@tonic-gate &sp->s_targetinfo)) != DDI_SUCCESS) {
5030Sstevel@tonic-gate (void) t1394_detach(&sp->s_t1394_hdl, 0);
5040Sstevel@tonic-gate return (ret);
5050Sstevel@tonic-gate }
5060Sstevel@tonic-gate
5070Sstevel@tonic-gate return (DDI_SUCCESS);
5080Sstevel@tonic-gate }
5090Sstevel@tonic-gate
5100Sstevel@tonic-gate static void
scsa1394_detach_1394(scsa1394_state_t * sp)5110Sstevel@tonic-gate scsa1394_detach_1394(scsa1394_state_t *sp)
5120Sstevel@tonic-gate {
5130Sstevel@tonic-gate (void) t1394_detach(&sp->s_t1394_hdl, 0);
5140Sstevel@tonic-gate }
5150Sstevel@tonic-gate
5160Sstevel@tonic-gate static int
scsa1394_attach_threads(scsa1394_state_t * sp)5170Sstevel@tonic-gate scsa1394_attach_threads(scsa1394_state_t *sp)
5180Sstevel@tonic-gate {
5190Sstevel@tonic-gate char name[16];
5200Sstevel@tonic-gate int nthr;
5210Sstevel@tonic-gate
5220Sstevel@tonic-gate nthr = sp->s_nluns;
5230Sstevel@tonic-gate (void) snprintf(name, sizeof (name), "scsa1394%d", sp->s_instance);
5240Sstevel@tonic-gate if ((sp->s_taskq = ddi_taskq_create(sp->s_dip, name, nthr,
5250Sstevel@tonic-gate TASKQ_DEFAULTPRI, 0)) == NULL) {
5260Sstevel@tonic-gate return (DDI_FAILURE);
5270Sstevel@tonic-gate }
5280Sstevel@tonic-gate
5290Sstevel@tonic-gate if (scsa1394_sbp2_threads_init(sp) != DDI_SUCCESS) {
5300Sstevel@tonic-gate ddi_taskq_destroy(sp->s_taskq);
5310Sstevel@tonic-gate return (DDI_FAILURE);
5320Sstevel@tonic-gate }
5330Sstevel@tonic-gate
5340Sstevel@tonic-gate return (DDI_SUCCESS);
5350Sstevel@tonic-gate }
5360Sstevel@tonic-gate
5370Sstevel@tonic-gate static void
scsa1394_detach_threads(scsa1394_state_t * sp)5380Sstevel@tonic-gate scsa1394_detach_threads(scsa1394_state_t *sp)
5390Sstevel@tonic-gate {
5400Sstevel@tonic-gate scsa1394_sbp2_threads_fini(sp);
5410Sstevel@tonic-gate ddi_taskq_destroy(sp->s_taskq);
5420Sstevel@tonic-gate }
5430Sstevel@tonic-gate
5440Sstevel@tonic-gate static int
scsa1394_attach_scsa(scsa1394_state_t * sp)5450Sstevel@tonic-gate scsa1394_attach_scsa(scsa1394_state_t *sp)
5460Sstevel@tonic-gate {
5470Sstevel@tonic-gate scsi_hba_tran_t *tran;
5480Sstevel@tonic-gate int ret;
5490Sstevel@tonic-gate
5500Sstevel@tonic-gate sp->s_tran = tran = scsi_hba_tran_alloc(sp->s_dip, SCSI_HBA_CANSLEEP);
5510Sstevel@tonic-gate
5520Sstevel@tonic-gate tran->tran_hba_private = sp;
5530Sstevel@tonic-gate tran->tran_tgt_private = NULL;
5540Sstevel@tonic-gate tran->tran_tgt_init = scsa1394_scsi_tgt_init;
5550Sstevel@tonic-gate tran->tran_tgt_probe = scsa1394_scsi_tgt_probe;
5560Sstevel@tonic-gate tran->tran_tgt_free = scsa1394_scsi_tgt_free;
5570Sstevel@tonic-gate tran->tran_start = scsa1394_scsi_start;
5580Sstevel@tonic-gate tran->tran_abort = scsa1394_scsi_abort;
5590Sstevel@tonic-gate tran->tran_reset = scsa1394_scsi_reset;
5600Sstevel@tonic-gate tran->tran_getcap = scsa1394_scsi_getcap;
5610Sstevel@tonic-gate tran->tran_setcap = scsa1394_scsi_setcap;
5620Sstevel@tonic-gate tran->tran_init_pkt = scsa1394_scsi_init_pkt;
5630Sstevel@tonic-gate tran->tran_destroy_pkt = scsa1394_scsi_destroy_pkt;
5640Sstevel@tonic-gate tran->tran_dmafree = scsa1394_scsi_dmafree;
5650Sstevel@tonic-gate tran->tran_sync_pkt = scsa1394_scsi_sync_pkt;
5660Sstevel@tonic-gate tran->tran_reset_notify = NULL;
5670Sstevel@tonic-gate tran->tran_get_bus_addr = NULL;
5680Sstevel@tonic-gate tran->tran_get_name = NULL;
5690Sstevel@tonic-gate tran->tran_bus_reset = NULL;
5700Sstevel@tonic-gate tran->tran_quiesce = NULL;
5710Sstevel@tonic-gate tran->tran_unquiesce = NULL;
5720Sstevel@tonic-gate tran->tran_get_eventcookie = NULL;
5730Sstevel@tonic-gate tran->tran_add_eventcall = NULL;
5740Sstevel@tonic-gate tran->tran_remove_eventcall = NULL;
5750Sstevel@tonic-gate tran->tran_post_event = NULL;
5760Sstevel@tonic-gate tran->tran_bus_config = scsa1394_scsi_bus_config;
5770Sstevel@tonic-gate tran->tran_bus_unconfig = scsa1394_scsi_bus_unconfig;
5780Sstevel@tonic-gate
5790Sstevel@tonic-gate if ((ret = scsi_hba_attach_setup(sp->s_dip, &sp->s_attachinfo.dma_attr,
5800Sstevel@tonic-gate tran, 0)) != DDI_SUCCESS) {
5810Sstevel@tonic-gate scsi_hba_tran_free(tran);
5820Sstevel@tonic-gate return (ret);
5830Sstevel@tonic-gate }
5840Sstevel@tonic-gate
5850Sstevel@tonic-gate return (DDI_SUCCESS);
5860Sstevel@tonic-gate }
5870Sstevel@tonic-gate
5880Sstevel@tonic-gate static void
scsa1394_detach_scsa(scsa1394_state_t * sp)5890Sstevel@tonic-gate scsa1394_detach_scsa(scsa1394_state_t *sp)
5900Sstevel@tonic-gate {
5910Sstevel@tonic-gate int ret;
5920Sstevel@tonic-gate
5930Sstevel@tonic-gate ret = scsi_hba_detach(sp->s_dip);
5940Sstevel@tonic-gate ASSERT(ret == DDI_SUCCESS);
5950Sstevel@tonic-gate
5960Sstevel@tonic-gate scsi_hba_tran_free(sp->s_tran);
5970Sstevel@tonic-gate }
5980Sstevel@tonic-gate
5990Sstevel@tonic-gate static int
scsa1394_create_cmd_cache(scsa1394_state_t * sp)6000Sstevel@tonic-gate scsa1394_create_cmd_cache(scsa1394_state_t *sp)
6010Sstevel@tonic-gate {
6020Sstevel@tonic-gate char name[64];
6030Sstevel@tonic-gate
6040Sstevel@tonic-gate (void) sprintf(name, "scsa1394%d_cache", sp->s_instance);
6050Sstevel@tonic-gate sp->s_cmd_cache = kmem_cache_create(name,
6066640Scth SCSA1394_CMD_SIZE, sizeof (void *),
6070Sstevel@tonic-gate scsa1394_cmd_cache_constructor, scsa1394_cmd_cache_destructor,
6080Sstevel@tonic-gate NULL, (void *)sp, NULL, 0);
6090Sstevel@tonic-gate
6100Sstevel@tonic-gate return ((sp->s_cmd_cache == NULL) ? DDI_FAILURE : DDI_SUCCESS);
6110Sstevel@tonic-gate }
6120Sstevel@tonic-gate
6130Sstevel@tonic-gate static void
scsa1394_destroy_cmd_cache(scsa1394_state_t * sp)6140Sstevel@tonic-gate scsa1394_destroy_cmd_cache(scsa1394_state_t *sp)
6150Sstevel@tonic-gate {
6160Sstevel@tonic-gate kmem_cache_destroy(sp->s_cmd_cache);
6170Sstevel@tonic-gate }
6180Sstevel@tonic-gate
6190Sstevel@tonic-gate static int
scsa1394_add_events(scsa1394_state_t * sp)6200Sstevel@tonic-gate scsa1394_add_events(scsa1394_state_t *sp)
6210Sstevel@tonic-gate {
6220Sstevel@tonic-gate ddi_eventcookie_t br_evc, rem_evc, ins_evc;
6230Sstevel@tonic-gate
6240Sstevel@tonic-gate if (ddi_get_eventcookie(sp->s_dip, DDI_DEVI_BUS_RESET_EVENT,
6250Sstevel@tonic-gate &br_evc) != DDI_SUCCESS) {
6260Sstevel@tonic-gate return (DDI_FAILURE);
6270Sstevel@tonic-gate }
6280Sstevel@tonic-gate if (ddi_add_event_handler(sp->s_dip, br_evc, scsa1394_bus_reset,
6290Sstevel@tonic-gate sp, &sp->s_reset_cb_id) != DDI_SUCCESS) {
6300Sstevel@tonic-gate return (DDI_FAILURE);
6310Sstevel@tonic-gate }
6320Sstevel@tonic-gate
6330Sstevel@tonic-gate if (ddi_get_eventcookie(sp->s_dip, DDI_DEVI_REMOVE_EVENT,
6340Sstevel@tonic-gate &rem_evc) != DDI_SUCCESS) {
6350Sstevel@tonic-gate (void) ddi_remove_event_handler(sp->s_reset_cb_id);
6360Sstevel@tonic-gate return (DDI_FAILURE);
6370Sstevel@tonic-gate }
6380Sstevel@tonic-gate if (ddi_add_event_handler(sp->s_dip, rem_evc, scsa1394_disconnect,
6390Sstevel@tonic-gate sp, &sp->s_remove_cb_id) != DDI_SUCCESS) {
6400Sstevel@tonic-gate (void) ddi_remove_event_handler(sp->s_reset_cb_id);
6410Sstevel@tonic-gate return (DDI_FAILURE);
6420Sstevel@tonic-gate }
6430Sstevel@tonic-gate
6440Sstevel@tonic-gate if (ddi_get_eventcookie(sp->s_dip, DDI_DEVI_INSERT_EVENT,
6450Sstevel@tonic-gate &ins_evc) != DDI_SUCCESS) {
6460Sstevel@tonic-gate (void) ddi_remove_event_handler(sp->s_remove_cb_id);
6470Sstevel@tonic-gate (void) ddi_remove_event_handler(sp->s_reset_cb_id);
6480Sstevel@tonic-gate return (DDI_FAILURE);
6490Sstevel@tonic-gate }
6500Sstevel@tonic-gate if (ddi_add_event_handler(sp->s_dip, ins_evc, scsa1394_reconnect,
6510Sstevel@tonic-gate sp, &sp->s_insert_cb_id) != DDI_SUCCESS) {
6520Sstevel@tonic-gate (void) ddi_remove_event_handler(sp->s_remove_cb_id);
6530Sstevel@tonic-gate (void) ddi_remove_event_handler(sp->s_reset_cb_id);
6540Sstevel@tonic-gate return (DDI_FAILURE);
6550Sstevel@tonic-gate }
6560Sstevel@tonic-gate
6570Sstevel@tonic-gate return (DDI_SUCCESS);
6580Sstevel@tonic-gate }
6590Sstevel@tonic-gate
6600Sstevel@tonic-gate static void
scsa1394_remove_events(scsa1394_state_t * sp)6610Sstevel@tonic-gate scsa1394_remove_events(scsa1394_state_t *sp)
6620Sstevel@tonic-gate {
6630Sstevel@tonic-gate ddi_eventcookie_t evc;
6640Sstevel@tonic-gate
6650Sstevel@tonic-gate if (ddi_get_eventcookie(sp->s_dip, DDI_DEVI_INSERT_EVENT,
6660Sstevel@tonic-gate &evc) == DDI_SUCCESS) {
6670Sstevel@tonic-gate (void) ddi_remove_event_handler(sp->s_insert_cb_id);
6680Sstevel@tonic-gate }
6690Sstevel@tonic-gate
6700Sstevel@tonic-gate if (ddi_get_eventcookie(sp->s_dip, DDI_DEVI_REMOVE_EVENT,
6710Sstevel@tonic-gate &evc) == DDI_SUCCESS) {
6720Sstevel@tonic-gate (void) ddi_remove_event_handler(sp->s_remove_cb_id);
6730Sstevel@tonic-gate }
6740Sstevel@tonic-gate
6750Sstevel@tonic-gate if (ddi_get_eventcookie(sp->s_dip, DDI_DEVI_BUS_RESET_EVENT,
6760Sstevel@tonic-gate &evc) == DDI_SUCCESS) {
6770Sstevel@tonic-gate (void) ddi_remove_event_handler(sp->s_reset_cb_id);
6780Sstevel@tonic-gate }
6790Sstevel@tonic-gate }
6800Sstevel@tonic-gate
6810Sstevel@tonic-gate /*
6820Sstevel@tonic-gate *
6830Sstevel@tonic-gate * --- device configuration
6840Sstevel@tonic-gate *
6850Sstevel@tonic-gate */
6860Sstevel@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)6870Sstevel@tonic-gate scsa1394_scsi_bus_config(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op,
6880Sstevel@tonic-gate void *arg, dev_info_t **child)
6890Sstevel@tonic-gate {
6900Sstevel@tonic-gate scsa1394_state_t *sp = SCSA1394_INST2STATE(ddi_get_instance(dip));
6910Sstevel@tonic-gate int circ;
6920Sstevel@tonic-gate int ret;
6930Sstevel@tonic-gate
6940Sstevel@tonic-gate if (scsa1394_bus_config_debug) {
6950Sstevel@tonic-gate flag |= NDI_DEVI_DEBUG;
6960Sstevel@tonic-gate }
6970Sstevel@tonic-gate
6980Sstevel@tonic-gate ndi_devi_enter(dip, &circ);
6990Sstevel@tonic-gate if (DEVI(dip)->devi_child == NULL) {
7000Sstevel@tonic-gate scsa1394_create_children(sp);
7010Sstevel@tonic-gate }
7020Sstevel@tonic-gate ret = ndi_busop_bus_config(dip, flag, op, arg, child, 0);
7030Sstevel@tonic-gate ndi_devi_exit(dip, circ);
7040Sstevel@tonic-gate
7050Sstevel@tonic-gate return (ret);
7060Sstevel@tonic-gate }
7070Sstevel@tonic-gate
7080Sstevel@tonic-gate static int
scsa1394_scsi_bus_unconfig(dev_info_t * dip,uint_t flag,ddi_bus_config_op_t op,void * arg)7090Sstevel@tonic-gate scsa1394_scsi_bus_unconfig(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op,
7100Sstevel@tonic-gate void *arg)
7110Sstevel@tonic-gate {
7120Sstevel@tonic-gate scsa1394_state_t *sp = SCSA1394_INST2STATE(ddi_get_instance(dip));
7130Sstevel@tonic-gate int circ;
7140Sstevel@tonic-gate int ret;
7150Sstevel@tonic-gate uint_t saved_flag = flag;
7160Sstevel@tonic-gate
7170Sstevel@tonic-gate if (scsa1394_bus_config_debug) {
7180Sstevel@tonic-gate flag |= NDI_DEVI_DEBUG;
7190Sstevel@tonic-gate }
7200Sstevel@tonic-gate
7210Sstevel@tonic-gate /*
7220Sstevel@tonic-gate * First offline and if offlining successful, then remove children.
7230Sstevel@tonic-gate */
7240Sstevel@tonic-gate if (op == BUS_UNCONFIG_ALL) {
7250Sstevel@tonic-gate flag &= ~(NDI_DEVI_REMOVE | NDI_UNCONFIG);
7260Sstevel@tonic-gate }
7270Sstevel@tonic-gate
7280Sstevel@tonic-gate ndi_devi_enter(dip, &circ);
7290Sstevel@tonic-gate
7300Sstevel@tonic-gate ret = ndi_busop_bus_unconfig(dip, flag, op, arg);
7310Sstevel@tonic-gate
7320Sstevel@tonic-gate /*
7330Sstevel@tonic-gate * If previous step was successful and not part of modunload daemon,
7340Sstevel@tonic-gate * attempt to remove children.
7350Sstevel@tonic-gate */
7360Sstevel@tonic-gate if ((op == BUS_UNCONFIG_ALL) && (ret == NDI_SUCCESS) &&
7370Sstevel@tonic-gate ((flag & NDI_AUTODETACH) == 0)) {
7380Sstevel@tonic-gate flag |= NDI_DEVI_REMOVE;
7390Sstevel@tonic-gate ret = ndi_busop_bus_unconfig(dip, flag, op, arg);
7400Sstevel@tonic-gate }
7410Sstevel@tonic-gate ndi_devi_exit(dip, circ);
7420Sstevel@tonic-gate
7430Sstevel@tonic-gate if ((ret != NDI_SUCCESS) && (op == BUS_UNCONFIG_ALL) &&
7440Sstevel@tonic-gate ((saved_flag & NDI_DEVI_REMOVE) != 0)) {
7450Sstevel@tonic-gate mutex_enter(&sp->s_mutex);
7460Sstevel@tonic-gate if (!sp->s_disconnect_warned) {
7470Sstevel@tonic-gate cmn_err(CE_WARN, "scsa1394(%d): "
7480Sstevel@tonic-gate "Disconnected device was busy, please reconnect.\n",
7490Sstevel@tonic-gate sp->s_instance);
7500Sstevel@tonic-gate sp->s_disconnect_warned = B_TRUE;
7510Sstevel@tonic-gate }
7520Sstevel@tonic-gate mutex_exit(&sp->s_mutex);
7530Sstevel@tonic-gate }
7540Sstevel@tonic-gate
7550Sstevel@tonic-gate return (ret);
7560Sstevel@tonic-gate }
7570Sstevel@tonic-gate
7580Sstevel@tonic-gate void
scsa1394_dtype2name(int dtype,char ** node_name,char ** driver_name)7590Sstevel@tonic-gate scsa1394_dtype2name(int dtype, char **node_name, char **driver_name)
7600Sstevel@tonic-gate {
7610Sstevel@tonic-gate static struct {
7620Sstevel@tonic-gate char *node_name;
7630Sstevel@tonic-gate char *driver_name;
7640Sstevel@tonic-gate } dtype2name[] = {
7650Sstevel@tonic-gate { "disk", "sd" }, /* DTYPE_DIRECT 0x00 */
7660Sstevel@tonic-gate { "tape", "st" }, /* DTYPE_SEQUENTIAL 0x01 */
7670Sstevel@tonic-gate { "printer", NULL }, /* DTYPE_PRINTER 0x02 */
7680Sstevel@tonic-gate { "processor", NULL }, /* DTYPE_PROCESSOR 0x03 */
7690Sstevel@tonic-gate { "worm", NULL }, /* DTYPE_WORM 0x04 */
7700Sstevel@tonic-gate { "disk", "sd" }, /* DTYPE_RODIRECT 0x05 */
7710Sstevel@tonic-gate { "scanner", NULL }, /* DTYPE_SCANNER 0x06 */
7720Sstevel@tonic-gate { "disk", "sd" }, /* DTYPE_OPTICAL 0x07 */
7730Sstevel@tonic-gate { "changer", NULL }, /* DTYPE_CHANGER 0x08 */
7740Sstevel@tonic-gate { "comm", NULL }, /* DTYPE_COMM 0x09 */
7750Sstevel@tonic-gate { "generic", NULL }, /* DTYPE_??? 0x0A */
7760Sstevel@tonic-gate { "generic", NULL }, /* DTYPE_??? 0x0B */
7770Sstevel@tonic-gate { "array_ctrl", NULL }, /* DTYPE_ARRAY_CTRL 0x0C */
7786881Sbharding { "esi", "ses" }, /* DTYPE_ESI 0x0D */
7790Sstevel@tonic-gate { "disk", "sd" } /* DTYPE_RBC 0x0E */
7800Sstevel@tonic-gate };
7810Sstevel@tonic-gate
7820Sstevel@tonic-gate if (dtype < NELEM(dtype2name)) {
7830Sstevel@tonic-gate *node_name = dtype2name[dtype].node_name;
7840Sstevel@tonic-gate *driver_name = dtype2name[dtype].driver_name;
7850Sstevel@tonic-gate } else {
7860Sstevel@tonic-gate *node_name = "generic";
7870Sstevel@tonic-gate *driver_name = NULL;
7880Sstevel@tonic-gate }
7890Sstevel@tonic-gate }
7900Sstevel@tonic-gate
7910Sstevel@tonic-gate static void
scsa1394_create_children(scsa1394_state_t * sp)7920Sstevel@tonic-gate scsa1394_create_children(scsa1394_state_t *sp)
7930Sstevel@tonic-gate {
7940Sstevel@tonic-gate char name[SCSA1394_COMPAT_MAX][16];
7950Sstevel@tonic-gate char *compatible[SCSA1394_COMPAT_MAX];
7960Sstevel@tonic-gate dev_info_t *cdip;
7970Sstevel@tonic-gate int i;
7980Sstevel@tonic-gate int dtype;
7990Sstevel@tonic-gate char *node_name;
8000Sstevel@tonic-gate char *driver_name;
8010Sstevel@tonic-gate int ret;
8020Sstevel@tonic-gate
8030Sstevel@tonic-gate bzero(name, sizeof (name));
8040Sstevel@tonic-gate (void) strcpy(name[0], "sd");
8050Sstevel@tonic-gate for (i = 0; i < SCSA1394_COMPAT_MAX; i++) {
8060Sstevel@tonic-gate compatible[i] = name[i];
8070Sstevel@tonic-gate }
8080Sstevel@tonic-gate
8090Sstevel@tonic-gate for (i = 0; i < sp->s_nluns; i++) {
8100Sstevel@tonic-gate dtype = scsa1394_sbp2_get_lun_type(&sp->s_lun[i]);
8110Sstevel@tonic-gate scsa1394_dtype2name(dtype, &node_name, &driver_name);
8120Sstevel@tonic-gate
8130Sstevel@tonic-gate ndi_devi_alloc_sleep(sp->s_dip, node_name,
814789Sahrens (pnode_t)DEVI_SID_NODEID, &cdip);
8150Sstevel@tonic-gate
816*10696SDavid.Hollister@Sun.COM ret = ndi_prop_update_int(DDI_DEV_T_NONE, cdip,
817*10696SDavid.Hollister@Sun.COM SCSI_ADDR_PROP_TARGET, 0);
8180Sstevel@tonic-gate if (ret != DDI_PROP_SUCCESS) {
8190Sstevel@tonic-gate (void) ndi_devi_free(cdip);
8200Sstevel@tonic-gate continue;
8210Sstevel@tonic-gate }
8220Sstevel@tonic-gate
823*10696SDavid.Hollister@Sun.COM ret = ndi_prop_update_int(DDI_DEV_T_NONE, cdip,
824*10696SDavid.Hollister@Sun.COM SCSI_ADDR_PROP_LUN, i);
8250Sstevel@tonic-gate if (ret != DDI_PROP_SUCCESS) {
8260Sstevel@tonic-gate ddi_prop_remove_all(cdip);
8270Sstevel@tonic-gate (void) ndi_devi_free(cdip);
8280Sstevel@tonic-gate continue;
8290Sstevel@tonic-gate }
8300Sstevel@tonic-gate
8311415Scg149915 /*
8321415Scg149915 * Some devices don't support LOG SENSE, so tell
8331415Scg149915 * sd driver not to send this command.
8341415Scg149915 */
8351415Scg149915 ret = ndi_prop_update_int(DDI_DEV_T_NONE, cdip,
8361415Scg149915 "pm-capable", 1);
8371415Scg149915 if (ret != DDI_PROP_SUCCESS) {
8381415Scg149915 ddi_prop_remove_all(cdip);
8391415Scg149915 (void) ndi_devi_free(cdip);
8401415Scg149915 continue;
8411415Scg149915 }
8421415Scg149915
8431415Scg149915 ret = ndi_prop_create_boolean(DDI_DEV_T_NONE, cdip,
8441415Scg149915 "hotpluggable");
8451415Scg149915 if (ret != DDI_PROP_SUCCESS) {
8461415Scg149915 ddi_prop_remove_all(cdip);
8471415Scg149915 (void) ndi_devi_free(cdip);
8481415Scg149915 continue;
8491415Scg149915 }
8501415Scg149915
8510Sstevel@tonic-gate if (driver_name) {
8520Sstevel@tonic-gate compatible[0] = driver_name;
8530Sstevel@tonic-gate ret = ndi_prop_update_string_array(DDI_DEV_T_NONE, cdip,
8540Sstevel@tonic-gate "compatible", (char **)compatible,
8550Sstevel@tonic-gate SCSA1394_COMPAT_MAX);
8560Sstevel@tonic-gate if (ret != DDI_PROP_SUCCESS) {
8570Sstevel@tonic-gate ddi_prop_remove_all(cdip);
8580Sstevel@tonic-gate (void) ndi_devi_free(cdip);
8590Sstevel@tonic-gate continue;
8600Sstevel@tonic-gate }
8610Sstevel@tonic-gate }
8620Sstevel@tonic-gate
8630Sstevel@tonic-gate /*
8640Sstevel@tonic-gate * add property "scsa1394" to distinguish from others' children
8650Sstevel@tonic-gate */
8660Sstevel@tonic-gate ret = ndi_prop_create_boolean(DDI_DEV_T_NONE, cdip, "scsa1394");
8670Sstevel@tonic-gate if (ret != DDI_PROP_SUCCESS) {
8680Sstevel@tonic-gate ddi_prop_remove_all(cdip);
8690Sstevel@tonic-gate (void) ndi_devi_free(cdip);
8700Sstevel@tonic-gate continue;
8710Sstevel@tonic-gate }
8720Sstevel@tonic-gate
8730Sstevel@tonic-gate (void) ddi_initchild(sp->s_dip, cdip);
8740Sstevel@tonic-gate }
8750Sstevel@tonic-gate }
8760Sstevel@tonic-gate
8770Sstevel@tonic-gate /*ARGSUSED*/
8780Sstevel@tonic-gate static void
scsa1394_bus_reset(dev_info_t * dip,ddi_eventcookie_t evc,void * arg,void * data)8790Sstevel@tonic-gate scsa1394_bus_reset(dev_info_t *dip, ddi_eventcookie_t evc, void *arg,
8800Sstevel@tonic-gate void *data)
8810Sstevel@tonic-gate {
8820Sstevel@tonic-gate scsa1394_state_t *sp = arg;
8830Sstevel@tonic-gate
8840Sstevel@tonic-gate if (sp != NULL) {
8850Sstevel@tonic-gate mutex_enter(&sp->s_mutex);
8860Sstevel@tonic-gate if (sp->s_dev_state == SCSA1394_DEV_DISCONNECTED) {
8870Sstevel@tonic-gate mutex_exit(&sp->s_mutex);
8880Sstevel@tonic-gate return;
8890Sstevel@tonic-gate }
8900Sstevel@tonic-gate sp->s_stat.stat_bus_reset_cnt++;
8910Sstevel@tonic-gate sp->s_dev_state = SCSA1394_DEV_BUS_RESET;
8920Sstevel@tonic-gate sp->s_attachinfo.localinfo = *(t1394_localinfo_t *)data;
8930Sstevel@tonic-gate mutex_exit(&sp->s_mutex);
8940Sstevel@tonic-gate
8950Sstevel@tonic-gate scsa1394_sbp2_req(sp, 0, SCSA1394_THREQ_BUS_RESET);
8960Sstevel@tonic-gate }
8970Sstevel@tonic-gate }
8980Sstevel@tonic-gate
8990Sstevel@tonic-gate /*ARGSUSED*/
9000Sstevel@tonic-gate static void
scsa1394_disconnect(dev_info_t * dip,ddi_eventcookie_t evc,void * arg,void * data)9010Sstevel@tonic-gate scsa1394_disconnect(dev_info_t *dip, ddi_eventcookie_t evc, void *arg,
9020Sstevel@tonic-gate void *data)
9030Sstevel@tonic-gate {
9040Sstevel@tonic-gate scsa1394_state_t *sp = arg;
9050Sstevel@tonic-gate int circ;
9060Sstevel@tonic-gate dev_info_t *cdip, *cdip_next;
9070Sstevel@tonic-gate
9080Sstevel@tonic-gate if (sp == NULL) {
9090Sstevel@tonic-gate return;
9100Sstevel@tonic-gate }
9110Sstevel@tonic-gate
9120Sstevel@tonic-gate mutex_enter(&sp->s_mutex);
9130Sstevel@tonic-gate sp->s_stat.stat_disconnect_cnt++;
9140Sstevel@tonic-gate sp->s_dev_state = SCSA1394_DEV_DISCONNECTED;
9150Sstevel@tonic-gate mutex_exit(&sp->s_mutex);
9160Sstevel@tonic-gate
9170Sstevel@tonic-gate scsa1394_sbp2_disconnect(sp);
9180Sstevel@tonic-gate
9190Sstevel@tonic-gate ndi_devi_enter(dip, &circ);
9200Sstevel@tonic-gate for (cdip = ddi_get_child(dip); cdip != NULL; cdip = cdip_next) {
9210Sstevel@tonic-gate cdip_next = ddi_get_next_sibling(cdip);
9220Sstevel@tonic-gate
9230Sstevel@tonic-gate mutex_enter(&DEVI(cdip)->devi_lock);
9240Sstevel@tonic-gate DEVI_SET_DEVICE_REMOVED(cdip);
9250Sstevel@tonic-gate mutex_exit(&DEVI(cdip)->devi_lock);
9260Sstevel@tonic-gate }
9270Sstevel@tonic-gate ndi_devi_exit(dip, circ);
9280Sstevel@tonic-gate }
9290Sstevel@tonic-gate
9300Sstevel@tonic-gate /*ARGSUSED*/
9310Sstevel@tonic-gate static void
scsa1394_reconnect(dev_info_t * dip,ddi_eventcookie_t evc,void * arg,void * data)9320Sstevel@tonic-gate scsa1394_reconnect(dev_info_t *dip, ddi_eventcookie_t evc, void *arg,
9330Sstevel@tonic-gate void *data)
9340Sstevel@tonic-gate {
9350Sstevel@tonic-gate scsa1394_state_t *sp = arg;
9360Sstevel@tonic-gate int circ;
9370Sstevel@tonic-gate dev_info_t *cdip, *cdip_next;
9380Sstevel@tonic-gate
9390Sstevel@tonic-gate if (sp == NULL) {
9400Sstevel@tonic-gate return;
9410Sstevel@tonic-gate }
9420Sstevel@tonic-gate
9430Sstevel@tonic-gate mutex_enter(&sp->s_mutex);
9440Sstevel@tonic-gate sp->s_stat.stat_reconnect_cnt++;
9450Sstevel@tonic-gate sp->s_attachinfo.localinfo = *(t1394_localinfo_t *)data;
9460Sstevel@tonic-gate sp->s_disconnect_warned = B_FALSE;
9470Sstevel@tonic-gate mutex_exit(&sp->s_mutex);
9480Sstevel@tonic-gate
9490Sstevel@tonic-gate ndi_devi_enter(dip, &circ);
9500Sstevel@tonic-gate for (cdip = ddi_get_child(dip); cdip != NULL; cdip = cdip_next) {
9510Sstevel@tonic-gate cdip_next = ddi_get_next_sibling(cdip);
9520Sstevel@tonic-gate
9530Sstevel@tonic-gate mutex_enter(&DEVI(cdip)->devi_lock);
9540Sstevel@tonic-gate DEVI_SET_DEVICE_REINSERTED(cdip);
9550Sstevel@tonic-gate mutex_exit(&DEVI(cdip)->devi_lock);
9560Sstevel@tonic-gate }
9570Sstevel@tonic-gate ndi_devi_exit(dip, circ);
9580Sstevel@tonic-gate
9590Sstevel@tonic-gate scsa1394_sbp2_req(sp, 0, SCSA1394_THREQ_RECONNECT);
9600Sstevel@tonic-gate }
9610Sstevel@tonic-gate
9620Sstevel@tonic-gate /*
9630Sstevel@tonic-gate *
9640Sstevel@tonic-gate * --- SCSA entry points
9650Sstevel@tonic-gate *
9660Sstevel@tonic-gate */
9670Sstevel@tonic-gate /*ARGSUSED*/
9680Sstevel@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)9690Sstevel@tonic-gate scsa1394_scsi_tgt_init(dev_info_t *dip, dev_info_t *cdip, scsi_hba_tran_t *tran,
9700Sstevel@tonic-gate struct scsi_device *sd)
9710Sstevel@tonic-gate {
9720Sstevel@tonic-gate scsa1394_state_t *sp = (scsa1394_state_t *)tran->tran_hba_private;
9730Sstevel@tonic-gate int lun;
9740Sstevel@tonic-gate int plen = sizeof (int);
9750Sstevel@tonic-gate int ret = DDI_FAILURE;
9760Sstevel@tonic-gate
9770Sstevel@tonic-gate if (ddi_prop_op(DDI_DEV_T_ANY, cdip, PROP_LEN_AND_VAL_BUF,
978*10696SDavid.Hollister@Sun.COM DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, SCSI_ADDR_PROP_LUN,
979*10696SDavid.Hollister@Sun.COM (caddr_t)&lun, &plen) != DDI_PROP_SUCCESS) {
9800Sstevel@tonic-gate return (DDI_FAILURE);
9810Sstevel@tonic-gate }
9820Sstevel@tonic-gate
9830Sstevel@tonic-gate if (!scsa1394_is_my_child(cdip)) {
9840Sstevel@tonic-gate /*
9850Sstevel@tonic-gate * add property "scsa1394" to distinguish from others' children
9860Sstevel@tonic-gate */
9870Sstevel@tonic-gate ret = ndi_prop_create_boolean(DDI_DEV_T_NONE, cdip, "scsa1394");
9880Sstevel@tonic-gate if (ret != DDI_PROP_SUCCESS) {
9890Sstevel@tonic-gate return (DDI_FAILURE);
9900Sstevel@tonic-gate }
9910Sstevel@tonic-gate
992276Sartem if (scsa1394_dev_is_online(sp)) {
993276Sartem return (scsa1394_sbp2_login(sp, lun));
994276Sartem } else {
995276Sartem return (DDI_FAILURE);
996276Sartem }
9970Sstevel@tonic-gate }
9980Sstevel@tonic-gate
999276Sartem if ((lun >= sp->s_nluns) || (sp->s_lun[lun].l_cdip != NULL) ||
1000276Sartem !scsa1394_dev_is_online(sp)) {
10010Sstevel@tonic-gate return (DDI_FAILURE);
10020Sstevel@tonic-gate }
10030Sstevel@tonic-gate
10040Sstevel@tonic-gate if ((ret = scsa1394_sbp2_login(sp, lun)) == DDI_SUCCESS) {
10050Sstevel@tonic-gate sp->s_lun[lun].l_cdip = cdip;
10060Sstevel@tonic-gate }
10070Sstevel@tonic-gate return (ret);
10080Sstevel@tonic-gate }
10090Sstevel@tonic-gate
10100Sstevel@tonic-gate /*ARGSUSED*/
10110Sstevel@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)10120Sstevel@tonic-gate scsa1394_scsi_tgt_free(dev_info_t *dip, dev_info_t *cdip, scsi_hba_tran_t *tran,
10130Sstevel@tonic-gate struct scsi_device *sd)
10140Sstevel@tonic-gate {
10150Sstevel@tonic-gate scsa1394_state_t *sp = (scsa1394_state_t *)tran->tran_hba_private;
10160Sstevel@tonic-gate int lun;
10170Sstevel@tonic-gate int plen = sizeof (int);
10180Sstevel@tonic-gate
10190Sstevel@tonic-gate if (!scsa1394_is_my_child(cdip)) {
10200Sstevel@tonic-gate return;
10210Sstevel@tonic-gate }
10220Sstevel@tonic-gate
10230Sstevel@tonic-gate if (ddi_prop_op(DDI_DEV_T_ANY, cdip, PROP_LEN_AND_VAL_BUF,
1024*10696SDavid.Hollister@Sun.COM DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, SCSI_ADDR_PROP_LUN,
1025*10696SDavid.Hollister@Sun.COM (caddr_t)&lun, &plen) != DDI_PROP_SUCCESS) {
10260Sstevel@tonic-gate return;
10270Sstevel@tonic-gate }
10280Sstevel@tonic-gate
10290Sstevel@tonic-gate if ((lun < sp->s_nluns) && (sp->s_lun[lun].l_cdip == cdip)) {
10300Sstevel@tonic-gate if (scsa1394_dev_is_online(sp)) {
10310Sstevel@tonic-gate scsa1394_sbp2_logout(sp, lun, B_TRUE);
10320Sstevel@tonic-gate }
10330Sstevel@tonic-gate sp->s_lun[lun].l_cdip = NULL;
10340Sstevel@tonic-gate }
10350Sstevel@tonic-gate }
10360Sstevel@tonic-gate
10370Sstevel@tonic-gate static int
scsa1394_scsi_tgt_probe(struct scsi_device * sd,int (* waitfunc)())10380Sstevel@tonic-gate scsa1394_scsi_tgt_probe(struct scsi_device *sd, int (*waitfunc)())
10390Sstevel@tonic-gate {
10400Sstevel@tonic-gate dev_info_t *dip = ddi_get_parent(sd->sd_dev);
10410Sstevel@tonic-gate scsi_hba_tran_t *tran = (scsi_hba_tran_t *)ddi_get_driver_private(dip);
10420Sstevel@tonic-gate scsa1394_state_t *sp = (scsa1394_state_t *)tran->tran_hba_private;
10430Sstevel@tonic-gate scsa1394_lun_t *lp;
10440Sstevel@tonic-gate
10450Sstevel@tonic-gate if (!scsa1394_dev_is_online(sp)) {
10460Sstevel@tonic-gate return (SCSIPROBE_FAILURE);
10470Sstevel@tonic-gate }
10480Sstevel@tonic-gate lp = &sp->s_lun[sd->sd_address.a_lun];
10490Sstevel@tonic-gate
10500Sstevel@tonic-gate if (scsa1394_probe_g0_nodata(sd, waitfunc,
10510Sstevel@tonic-gate SCMD_TEST_UNIT_READY, 0, 0) != SCSIPROBE_EXISTS) {
10520Sstevel@tonic-gate lp->l_nosup_tur = B_TRUE;
10530Sstevel@tonic-gate (void) scsa1394_sbp2_reset(lp, RESET_LUN, NULL);
10540Sstevel@tonic-gate }
10550Sstevel@tonic-gate if (scsa1394_probe_g0_nodata(sd, waitfunc,
10560Sstevel@tonic-gate SCMD_START_STOP, 0, 1) != SCSIPROBE_EXISTS) {
10570Sstevel@tonic-gate lp->l_nosup_start_stop = B_TRUE;
10580Sstevel@tonic-gate }
10590Sstevel@tonic-gate
10600Sstevel@tonic-gate /* standard probe issues INQUIRY, which some devices may not support */
10610Sstevel@tonic-gate if (scsi_hba_probe(sd, waitfunc) != SCSIPROBE_EXISTS) {
10620Sstevel@tonic-gate lp->l_nosup_inquiry = B_TRUE;
10630Sstevel@tonic-gate scsa1394_sbp2_fake_inquiry(sp, &lp->l_fake_inq);
10640Sstevel@tonic-gate bcopy(&lp->l_fake_inq, sd->sd_inq, SUN_INQSIZE);
10650Sstevel@tonic-gate #ifndef __lock_lint
10660Sstevel@tonic-gate lp->l_rmb_orig = 1;
10670Sstevel@tonic-gate #endif
10680Sstevel@tonic-gate }
10690Sstevel@tonic-gate
10701415Scg149915 if (scsa1394_wrka_fake_rmb) {
10710Sstevel@tonic-gate sd->sd_inq->inq_rmb = 1;
10720Sstevel@tonic-gate }
10730Sstevel@tonic-gate
10740Sstevel@tonic-gate return (SCSIPROBE_EXISTS);
10750Sstevel@tonic-gate }
10760Sstevel@tonic-gate
10770Sstevel@tonic-gate static int
scsa1394_probe_g0_nodata(struct scsi_device * sd,int (* waitfunc)(),uchar_t cmd,uint_t addr,uint_t cnt)10780Sstevel@tonic-gate scsa1394_probe_g0_nodata(struct scsi_device *sd, int (*waitfunc)(),
10790Sstevel@tonic-gate uchar_t cmd, uint_t addr, uint_t cnt)
10800Sstevel@tonic-gate {
10810Sstevel@tonic-gate struct scsi_pkt *pkt;
10820Sstevel@tonic-gate int ret = SCSIPROBE_EXISTS;
10830Sstevel@tonic-gate
10840Sstevel@tonic-gate pkt = scsi_init_pkt(&sd->sd_address, NULL, NULL, CDB_GROUP0,
10850Sstevel@tonic-gate sizeof (struct scsi_arq_status), 0, PKT_CONSISTENT, waitfunc, NULL);
10860Sstevel@tonic-gate
10870Sstevel@tonic-gate if (pkt == NULL) {
10880Sstevel@tonic-gate return (SCSIPROBE_NOMEM);
10890Sstevel@tonic-gate }
10900Sstevel@tonic-gate
10910Sstevel@tonic-gate (void) scsi_setup_cdb((union scsi_cdb *)pkt->pkt_cdbp, cmd, addr, cnt,
10920Sstevel@tonic-gate 0);
10930Sstevel@tonic-gate ((union scsi_cdb *)(pkt)->pkt_cdbp)->scc_lun = sd->sd_address.a_lun;
10940Sstevel@tonic-gate pkt->pkt_flags = FLAG_NOINTR;
10950Sstevel@tonic-gate
10960Sstevel@tonic-gate if (scsa1394_probe_tran(pkt) < 0) {
10970Sstevel@tonic-gate if (pkt->pkt_reason == CMD_INCOMPLETE) {
10980Sstevel@tonic-gate ret = SCSIPROBE_NORESP;
10998763SAlan.Perry@Sun.COM } else if ((pkt->pkt_reason == CMD_TRAN_ERR) &&
11008763SAlan.Perry@Sun.COM ((*(pkt->pkt_scbp) & STATUS_MASK) == STATUS_CHECK) &&
11018763SAlan.Perry@Sun.COM (pkt->pkt_state & STATE_ARQ_DONE)) {
11028763SAlan.Perry@Sun.COM ret = SCSIPROBE_EXISTS;
11030Sstevel@tonic-gate } else {
11040Sstevel@tonic-gate ret = SCSIPROBE_FAILURE;
11050Sstevel@tonic-gate }
11060Sstevel@tonic-gate }
11070Sstevel@tonic-gate
11080Sstevel@tonic-gate scsi_destroy_pkt(pkt);
11090Sstevel@tonic-gate
11100Sstevel@tonic-gate return (ret);
11110Sstevel@tonic-gate }
11120Sstevel@tonic-gate
11130Sstevel@tonic-gate static int
scsa1394_probe_tran(struct scsi_pkt * pkt)11140Sstevel@tonic-gate scsa1394_probe_tran(struct scsi_pkt *pkt)
11150Sstevel@tonic-gate {
11160Sstevel@tonic-gate pkt->pkt_time = SCSA1394_PROBE_TIMEOUT;
11170Sstevel@tonic-gate
11180Sstevel@tonic-gate if (scsi_transport(pkt) != TRAN_ACCEPT) {
11190Sstevel@tonic-gate return (-1);
11200Sstevel@tonic-gate } else if ((pkt->pkt_reason == CMD_INCOMPLETE) &&
11210Sstevel@tonic-gate (pkt->pkt_state == 0)) {
11220Sstevel@tonic-gate return (-1);
11230Sstevel@tonic-gate } else if (pkt->pkt_reason != CMD_CMPLT) {
11240Sstevel@tonic-gate return (-1);
11250Sstevel@tonic-gate } else if (((*pkt->pkt_scbp) & STATUS_MASK) == STATUS_BUSY) {
11260Sstevel@tonic-gate return (0);
11270Sstevel@tonic-gate }
11280Sstevel@tonic-gate return (0);
11290Sstevel@tonic-gate }
11300Sstevel@tonic-gate
11310Sstevel@tonic-gate /*ARGSUSED*/
11320Sstevel@tonic-gate static int
scsa1394_scsi_abort(struct scsi_address * ap,struct scsi_pkt * pkt)11330Sstevel@tonic-gate scsa1394_scsi_abort(struct scsi_address *ap, struct scsi_pkt *pkt)
11340Sstevel@tonic-gate {
11350Sstevel@tonic-gate return (0);
11360Sstevel@tonic-gate }
11370Sstevel@tonic-gate
11380Sstevel@tonic-gate static int
scsa1394_scsi_reset(struct scsi_address * ap,int level)11390Sstevel@tonic-gate scsa1394_scsi_reset(struct scsi_address *ap, int level)
11400Sstevel@tonic-gate {
11410Sstevel@tonic-gate scsa1394_state_t *sp = ADDR2STATE(ap);
11420Sstevel@tonic-gate scsa1394_lun_t *lp;
11430Sstevel@tonic-gate int ret;
11440Sstevel@tonic-gate
11450Sstevel@tonic-gate switch (level) {
11460Sstevel@tonic-gate case RESET_ALL:
11470Sstevel@tonic-gate case RESET_TARGET:
11480Sstevel@tonic-gate lp = &sp->s_lun[0];
11490Sstevel@tonic-gate break;
11500Sstevel@tonic-gate case RESET_LUN:
11510Sstevel@tonic-gate lp = &sp->s_lun[ap->a_lun];
11520Sstevel@tonic-gate break;
11530Sstevel@tonic-gate default:
11540Sstevel@tonic-gate return (DDI_FAILURE);
11550Sstevel@tonic-gate }
11560Sstevel@tonic-gate
11570Sstevel@tonic-gate ret = scsa1394_sbp2_reset(lp, level, NULL);
11580Sstevel@tonic-gate
11590Sstevel@tonic-gate return ((ret == SBP2_SUCCESS) ? 1 : 0);
11600Sstevel@tonic-gate }
11610Sstevel@tonic-gate
11620Sstevel@tonic-gate /*ARGSUSED*/
11630Sstevel@tonic-gate static int
scsa1394_scsi_getcap(struct scsi_address * ap,char * cap,int whom)11640Sstevel@tonic-gate scsa1394_scsi_getcap(struct scsi_address *ap, char *cap, int whom)
11650Sstevel@tonic-gate {
11660Sstevel@tonic-gate scsa1394_state_t *sp = ADDR2STATE(ap);
11670Sstevel@tonic-gate size_t dev_bsize_cap;
11680Sstevel@tonic-gate int ret = -1;
11690Sstevel@tonic-gate
11700Sstevel@tonic-gate if (!scsa1394_dev_is_online(sp)) {
11710Sstevel@tonic-gate return (-1);
11720Sstevel@tonic-gate }
11730Sstevel@tonic-gate
11740Sstevel@tonic-gate if (cap == NULL) {
11750Sstevel@tonic-gate return (-1);
11760Sstevel@tonic-gate }
11770Sstevel@tonic-gate
11780Sstevel@tonic-gate switch (scsi_hba_lookup_capstr(cap)) {
11790Sstevel@tonic-gate case SCSI_CAP_DMA_MAX:
11800Sstevel@tonic-gate ret = sp->s_attachinfo.dma_attr.dma_attr_maxxfer;
11810Sstevel@tonic-gate break;
11820Sstevel@tonic-gate case SCSI_CAP_SCSI_VERSION:
11830Sstevel@tonic-gate ret = SCSI_VERSION_2;
11840Sstevel@tonic-gate break;
11850Sstevel@tonic-gate case SCSI_CAP_ARQ:
11860Sstevel@tonic-gate ret = 1;
11870Sstevel@tonic-gate break;
11880Sstevel@tonic-gate case SCSI_CAP_UNTAGGED_QING:
11890Sstevel@tonic-gate ret = 1;
11900Sstevel@tonic-gate break;
11910Sstevel@tonic-gate case SCSI_CAP_GEOMETRY:
11920Sstevel@tonic-gate dev_bsize_cap = sp->s_totalsec;
11930Sstevel@tonic-gate
11940Sstevel@tonic-gate if (sp->s_secsz > DEV_BSIZE) {
11950Sstevel@tonic-gate dev_bsize_cap *= sp->s_secsz / DEV_BSIZE;
11960Sstevel@tonic-gate } else if (sp->s_secsz < DEV_BSIZE) {
11970Sstevel@tonic-gate dev_bsize_cap /= DEV_BSIZE / sp->s_secsz;
11980Sstevel@tonic-gate }
11990Sstevel@tonic-gate
12000Sstevel@tonic-gate if (dev_bsize_cap < 65536 * 2 * 18) { /* < ~1GB */
12010Sstevel@tonic-gate /* unlabeled floppy, 18k per cylinder */
12020Sstevel@tonic-gate ret = ((2 << 16) | 18);
12030Sstevel@tonic-gate } else if (dev_bsize_cap < 65536 * 64 * 32) { /* < 64GB */
12040Sstevel@tonic-gate /* 1024k per cylinder */
12050Sstevel@tonic-gate ret = ((64 << 16) | 32);
12060Sstevel@tonic-gate } else if (dev_bsize_cap < 65536 * 255 * 63) { /* < ~500GB */
12070Sstevel@tonic-gate /* ~8m per cylinder */
12080Sstevel@tonic-gate ret = ((255 << 16) | 63);
12090Sstevel@tonic-gate } else { /* .. 8TB */
12100Sstevel@tonic-gate /* 64m per cylinder */
12110Sstevel@tonic-gate ret = ((512 << 16) | 256);
12120Sstevel@tonic-gate }
12130Sstevel@tonic-gate break;
12140Sstevel@tonic-gate default:
12150Sstevel@tonic-gate break;
12160Sstevel@tonic-gate }
12170Sstevel@tonic-gate
12180Sstevel@tonic-gate return (ret);
12190Sstevel@tonic-gate }
12200Sstevel@tonic-gate
12210Sstevel@tonic-gate /*ARGSUSED*/
12220Sstevel@tonic-gate static int
scsa1394_scsi_setcap(struct scsi_address * ap,char * cap,int value,int whom)12230Sstevel@tonic-gate scsa1394_scsi_setcap(struct scsi_address *ap, char *cap, int value, int whom)
12240Sstevel@tonic-gate {
12250Sstevel@tonic-gate scsa1394_state_t *sp = ADDR2STATE(ap);
12260Sstevel@tonic-gate int ret = -1;
12270Sstevel@tonic-gate
12280Sstevel@tonic-gate if (!scsa1394_dev_is_online(sp)) {
12290Sstevel@tonic-gate return (-1);
12300Sstevel@tonic-gate }
12310Sstevel@tonic-gate
12320Sstevel@tonic-gate switch (scsi_hba_lookup_capstr(cap)) {
12330Sstevel@tonic-gate case SCSI_CAP_ARQ:
12340Sstevel@tonic-gate ret = 1;
12350Sstevel@tonic-gate break;
12360Sstevel@tonic-gate case SCSI_CAP_DMA_MAX:
12370Sstevel@tonic-gate case SCSI_CAP_SCSI_VERSION:
12380Sstevel@tonic-gate case SCSI_CAP_UNTAGGED_QING:
12390Sstevel@tonic-gate /* supported but not settable */
12400Sstevel@tonic-gate ret = 0;
12410Sstevel@tonic-gate break;
12420Sstevel@tonic-gate case SCSI_CAP_SECTOR_SIZE:
12430Sstevel@tonic-gate if (value) {
12440Sstevel@tonic-gate sp->s_secsz = value;
12450Sstevel@tonic-gate }
12460Sstevel@tonic-gate break;
12470Sstevel@tonic-gate case SCSI_CAP_TOTAL_SECTORS:
12480Sstevel@tonic-gate if (value) {
12490Sstevel@tonic-gate sp->s_totalsec = value;
12500Sstevel@tonic-gate }
12510Sstevel@tonic-gate break;
12520Sstevel@tonic-gate default:
12530Sstevel@tonic-gate break;
12540Sstevel@tonic-gate }
12550Sstevel@tonic-gate
12560Sstevel@tonic-gate return (ret);
12570Sstevel@tonic-gate }
12580Sstevel@tonic-gate
12590Sstevel@tonic-gate /*ARGSUSED*/
12600Sstevel@tonic-gate static void
scsa1394_scsi_sync_pkt(struct scsi_address * ap,struct scsi_pkt * pkt)12610Sstevel@tonic-gate scsa1394_scsi_sync_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
12620Sstevel@tonic-gate {
12630Sstevel@tonic-gate scsa1394_cmd_t *cmd = PKT2CMD(pkt);
12640Sstevel@tonic-gate
12650Sstevel@tonic-gate if (cmd->sc_flags & SCSA1394_CMD_DMA_BUF_VALID) {
12660Sstevel@tonic-gate (void) ddi_dma_sync(cmd->sc_buf_dma_hdl, 0, 0,
12670Sstevel@tonic-gate (cmd->sc_flags & SCSA1394_CMD_READ) ?
12680Sstevel@tonic-gate DDI_DMA_SYNC_FORCPU : DDI_DMA_SYNC_FORDEV);
12690Sstevel@tonic-gate }
12700Sstevel@tonic-gate }
12710Sstevel@tonic-gate
12720Sstevel@tonic-gate /*
12730Sstevel@tonic-gate *
12740Sstevel@tonic-gate * --- pkt resource allocation routines
12750Sstevel@tonic-gate *
12760Sstevel@tonic-gate */
12770Sstevel@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)12780Sstevel@tonic-gate scsa1394_scsi_init_pkt(struct scsi_address *ap, struct scsi_pkt *pkt,
12790Sstevel@tonic-gate struct buf *bp, int cmdlen, int statuslen, int tgtlen, int flags,
12800Sstevel@tonic-gate int (*callback)(), caddr_t arg)
12810Sstevel@tonic-gate {
12820Sstevel@tonic-gate scsa1394_state_t *sp = ADDR2STATE(ap);
12830Sstevel@tonic-gate scsa1394_lun_t *lp;
12840Sstevel@tonic-gate scsa1394_cmd_t *cmd;
12850Sstevel@tonic-gate boolean_t is_new; /* new cmd is being allocated */
12860Sstevel@tonic-gate int kf = (callback == SLEEP_FUNC) ? KM_SLEEP : KM_NOSLEEP;
12870Sstevel@tonic-gate
12880Sstevel@tonic-gate if (ap->a_lun >= sp->s_nluns) {
12890Sstevel@tonic-gate return (NULL);
12900Sstevel@tonic-gate }
12910Sstevel@tonic-gate lp = &sp->s_lun[ap->a_lun];
12920Sstevel@tonic-gate
12930Sstevel@tonic-gate /*
12940Sstevel@tonic-gate * allocate cmd space
12950Sstevel@tonic-gate */
12960Sstevel@tonic-gate if (pkt == NULL) {
12970Sstevel@tonic-gate is_new = B_TRUE;
12980Sstevel@tonic-gate if ((cmd = kmem_cache_alloc(sp->s_cmd_cache, kf)) == NULL) {
12990Sstevel@tonic-gate return (NULL);
13000Sstevel@tonic-gate }
13010Sstevel@tonic-gate
13020Sstevel@tonic-gate /* initialize cmd */
13030Sstevel@tonic-gate pkt = &cmd->sc_scsi_pkt;
13040Sstevel@tonic-gate pkt->pkt_ha_private = cmd;
13050Sstevel@tonic-gate pkt->pkt_address = *ap;
13060Sstevel@tonic-gate pkt->pkt_private = cmd->sc_priv;
13070Sstevel@tonic-gate pkt->pkt_scbp = (uchar_t *)&cmd->sc_scb;
13080Sstevel@tonic-gate pkt->pkt_cdbp = (uchar_t *)&cmd->sc_pkt_cdb;
13090Sstevel@tonic-gate pkt->pkt_resid = 0;
13100Sstevel@tonic-gate
13110Sstevel@tonic-gate cmd->sc_lun = lp;
13120Sstevel@tonic-gate cmd->sc_pkt = pkt;
13130Sstevel@tonic-gate cmd->sc_cdb_len = cmdlen;
13140Sstevel@tonic-gate cmd->sc_scb_len = statuslen;
13150Sstevel@tonic-gate cmd->sc_priv_len = tgtlen;
13160Sstevel@tonic-gate
13170Sstevel@tonic-gate /* need external space? */
13180Sstevel@tonic-gate if ((cmdlen > sizeof (cmd->sc_pkt_cdb)) ||
13190Sstevel@tonic-gate (statuslen > sizeof (cmd->sc_scb)) ||
13200Sstevel@tonic-gate (tgtlen > sizeof (cmd->sc_priv))) {
13210Sstevel@tonic-gate if (scsa1394_cmd_ext_alloc(sp, cmd, kf) !=
13220Sstevel@tonic-gate DDI_SUCCESS) {
13230Sstevel@tonic-gate kmem_cache_free(sp->s_cmd_cache, cmd);
13240Sstevel@tonic-gate lp->l_stat.stat_err_pkt_kmem_alloc++;
13250Sstevel@tonic-gate return (NULL);
13260Sstevel@tonic-gate }
13270Sstevel@tonic-gate }
13280Sstevel@tonic-gate
13290Sstevel@tonic-gate /* allocate DMA resources for CDB */
13300Sstevel@tonic-gate if (scsa1394_cmd_cdb_dma_alloc(sp, cmd, flags, callback, arg) !=
13310Sstevel@tonic-gate DDI_SUCCESS) {
13320Sstevel@tonic-gate scsa1394_scsi_destroy_pkt(ap, pkt);
13330Sstevel@tonic-gate return (NULL);
13340Sstevel@tonic-gate }
13350Sstevel@tonic-gate } else {
13360Sstevel@tonic-gate is_new = B_FALSE;
13370Sstevel@tonic-gate cmd = PKT2CMD(pkt);
13380Sstevel@tonic-gate }
13390Sstevel@tonic-gate
13400Sstevel@tonic-gate cmd->sc_flags &= ~SCSA1394_CMD_RDWR;
13410Sstevel@tonic-gate
13420Sstevel@tonic-gate /* allocate/move DMA resources for data buffer */
13430Sstevel@tonic-gate if ((bp != NULL) && (bp->b_bcount > 0)) {
13440Sstevel@tonic-gate if ((cmd->sc_flags & SCSA1394_CMD_DMA_BUF_VALID) == 0) {
13450Sstevel@tonic-gate if (scsa1394_cmd_buf_dma_alloc(sp, cmd, flags, callback,
13460Sstevel@tonic-gate arg, bp) != DDI_SUCCESS) {
13470Sstevel@tonic-gate if (is_new) {
13480Sstevel@tonic-gate scsa1394_scsi_destroy_pkt(ap, pkt);
13490Sstevel@tonic-gate }
13500Sstevel@tonic-gate return (NULL);
13510Sstevel@tonic-gate }
13520Sstevel@tonic-gate } else {
13530Sstevel@tonic-gate if (scsa1394_cmd_buf_dma_move(sp, cmd) != DDI_SUCCESS) {
13540Sstevel@tonic-gate return (NULL);
13550Sstevel@tonic-gate }
13560Sstevel@tonic-gate }
13570Sstevel@tonic-gate
13580Sstevel@tonic-gate ASSERT(cmd->sc_win_len > 0);
13590Sstevel@tonic-gate pkt->pkt_resid = bp->b_bcount - cmd->sc_win_len;
13600Sstevel@tonic-gate }
13610Sstevel@tonic-gate
13620Sstevel@tonic-gate /*
13630Sstevel@tonic-gate * kernel virtual address may be required for certain workarounds
13640Sstevel@tonic-gate * and in case of B_PHYS or B_PAGEIO, bp_mapin() will get it for us
13650Sstevel@tonic-gate */
13660Sstevel@tonic-gate if ((bp != NULL) && ((bp->b_flags & (B_PAGEIO | B_PHYS)) != 0) &&
13670Sstevel@tonic-gate (bp->b_bcount < SCSA1394_MAPIN_SIZE_MAX) &&
13680Sstevel@tonic-gate ((cmd->sc_flags & SCSA1394_CMD_DMA_BUF_MAPIN) == 0)) {
13690Sstevel@tonic-gate bp_mapin(bp);
13700Sstevel@tonic-gate cmd->sc_flags |= SCSA1394_CMD_DMA_BUF_MAPIN;
13710Sstevel@tonic-gate }
13720Sstevel@tonic-gate
13730Sstevel@tonic-gate return (pkt);
13740Sstevel@tonic-gate }
13750Sstevel@tonic-gate
13760Sstevel@tonic-gate static void
scsa1394_scsi_destroy_pkt(struct scsi_address * ap,struct scsi_pkt * pkt)13770Sstevel@tonic-gate scsa1394_scsi_destroy_pkt(struct scsi_address *ap, struct scsi_pkt *pkt)
13780Sstevel@tonic-gate {
13790Sstevel@tonic-gate scsa1394_state_t *sp = ADDR2STATE(ap);
13800Sstevel@tonic-gate scsa1394_cmd_t *cmd = PKT2CMD(pkt);
13810Sstevel@tonic-gate
13820Sstevel@tonic-gate if (cmd->sc_flags & SCSA1394_CMD_DMA_BUF_VALID) {
13830Sstevel@tonic-gate scsa1394_cmd_buf_dma_free(sp, cmd);
13840Sstevel@tonic-gate }
13850Sstevel@tonic-gate if (cmd->sc_flags & SCSA1394_CMD_DMA_CDB_VALID) {
13860Sstevel@tonic-gate scsa1394_cmd_cdb_dma_free(sp, cmd);
13870Sstevel@tonic-gate }
13880Sstevel@tonic-gate if (cmd->sc_flags & SCSA1394_CMD_DMA_BUF_MAPIN) {
13890Sstevel@tonic-gate bp_mapout(cmd->sc_bp);
13900Sstevel@tonic-gate cmd->sc_flags &= ~SCSA1394_CMD_DMA_BUF_MAPIN;
13910Sstevel@tonic-gate }
13920Sstevel@tonic-gate if (cmd->sc_flags & SCSA1394_CMD_EXT) {
13930Sstevel@tonic-gate scsa1394_cmd_ext_free(sp, cmd);
13940Sstevel@tonic-gate }
13950Sstevel@tonic-gate
13960Sstevel@tonic-gate kmem_cache_free(sp->s_cmd_cache, cmd);
13970Sstevel@tonic-gate }
13980Sstevel@tonic-gate
13990Sstevel@tonic-gate static void
scsa1394_scsi_dmafree(struct scsi_address * ap,struct scsi_pkt * pkt)14000Sstevel@tonic-gate scsa1394_scsi_dmafree(struct scsi_address *ap, struct scsi_pkt *pkt)
14010Sstevel@tonic-gate {
14020Sstevel@tonic-gate scsa1394_state_t *sp = ADDR2STATE(ap);
14030Sstevel@tonic-gate scsa1394_cmd_t *cmd = PKT2CMD(pkt);
14040Sstevel@tonic-gate
14050Sstevel@tonic-gate if (cmd->sc_flags & SCSA1394_CMD_DMA_BUF_VALID) {
14060Sstevel@tonic-gate scsa1394_cmd_buf_dma_free(sp, cmd);
14070Sstevel@tonic-gate }
14080Sstevel@tonic-gate if (cmd->sc_flags & SCSA1394_CMD_DMA_BUF_MAPIN) {
14090Sstevel@tonic-gate bp_mapout(cmd->sc_bp);
14100Sstevel@tonic-gate cmd->sc_flags &= ~SCSA1394_CMD_DMA_BUF_MAPIN;
14110Sstevel@tonic-gate }
14120Sstevel@tonic-gate }
14130Sstevel@tonic-gate
14140Sstevel@tonic-gate /*ARGSUSED*/
14150Sstevel@tonic-gate static int
scsa1394_cmd_cache_constructor(void * buf,void * cdrarg,int kf)14160Sstevel@tonic-gate scsa1394_cmd_cache_constructor(void *buf, void *cdrarg, int kf)
14170Sstevel@tonic-gate {
14180Sstevel@tonic-gate scsa1394_cmd_t *cmd = buf;
14190Sstevel@tonic-gate
14206640Scth bzero(buf, SCSA1394_CMD_SIZE);
14210Sstevel@tonic-gate cmd->sc_task.ts_drv_priv = cmd;
14220Sstevel@tonic-gate
14230Sstevel@tonic-gate return (0);
14240Sstevel@tonic-gate }
14250Sstevel@tonic-gate
14260Sstevel@tonic-gate /*ARGSUSED*/
14270Sstevel@tonic-gate static void
scsa1394_cmd_cache_destructor(void * buf,void * cdrarg)14280Sstevel@tonic-gate scsa1394_cmd_cache_destructor(void *buf, void *cdrarg)
14290Sstevel@tonic-gate {
14300Sstevel@tonic-gate }
14310Sstevel@tonic-gate
14320Sstevel@tonic-gate /*
14330Sstevel@tonic-gate * allocate and deallocate external cmd space (ie. not part of scsa1394_cmd_t)
14340Sstevel@tonic-gate * for non-standard length cdb, pkt_private, status areas
14350Sstevel@tonic-gate */
14360Sstevel@tonic-gate static int
scsa1394_cmd_ext_alloc(scsa1394_state_t * sp,scsa1394_cmd_t * cmd,int kf)14370Sstevel@tonic-gate scsa1394_cmd_ext_alloc(scsa1394_state_t *sp, scsa1394_cmd_t *cmd, int kf)
14380Sstevel@tonic-gate {
14390Sstevel@tonic-gate struct scsi_pkt *pkt = cmd->sc_pkt;
14400Sstevel@tonic-gate void *buf;
14410Sstevel@tonic-gate
14420Sstevel@tonic-gate if (cmd->sc_cdb_len > sizeof (cmd->sc_pkt_cdb)) {
14430Sstevel@tonic-gate if ((buf = kmem_zalloc(cmd->sc_cdb_len, kf)) == NULL) {
14440Sstevel@tonic-gate return (DDI_FAILURE);
14450Sstevel@tonic-gate }
14460Sstevel@tonic-gate pkt->pkt_cdbp = buf;
14470Sstevel@tonic-gate cmd->sc_flags |= SCSA1394_CMD_CDB_EXT;
14480Sstevel@tonic-gate }
14490Sstevel@tonic-gate
14500Sstevel@tonic-gate if (cmd->sc_scb_len > sizeof (cmd->sc_scb)) {
14510Sstevel@tonic-gate if ((buf = kmem_zalloc(cmd->sc_scb_len, kf)) == NULL) {
14520Sstevel@tonic-gate scsa1394_cmd_ext_free(sp, cmd);
14530Sstevel@tonic-gate return (DDI_FAILURE);
14540Sstevel@tonic-gate }
14550Sstevel@tonic-gate pkt->pkt_scbp = buf;
14560Sstevel@tonic-gate cmd->sc_flags |= SCSA1394_CMD_SCB_EXT;
14570Sstevel@tonic-gate }
14580Sstevel@tonic-gate
14590Sstevel@tonic-gate if (cmd->sc_priv_len > sizeof (cmd->sc_priv)) {
14600Sstevel@tonic-gate if ((buf = kmem_zalloc(cmd->sc_priv_len, kf)) == NULL) {
14610Sstevel@tonic-gate scsa1394_cmd_ext_free(sp, cmd);
14620Sstevel@tonic-gate return (DDI_FAILURE);
14630Sstevel@tonic-gate }
14640Sstevel@tonic-gate pkt->pkt_private = buf;
14650Sstevel@tonic-gate cmd->sc_flags |= SCSA1394_CMD_PRIV_EXT;
14660Sstevel@tonic-gate }
14670Sstevel@tonic-gate
14680Sstevel@tonic-gate return (DDI_SUCCESS);
14690Sstevel@tonic-gate }
14700Sstevel@tonic-gate
14710Sstevel@tonic-gate /*ARGSUSED*/
14720Sstevel@tonic-gate static void
scsa1394_cmd_ext_free(scsa1394_state_t * sp,scsa1394_cmd_t * cmd)14730Sstevel@tonic-gate scsa1394_cmd_ext_free(scsa1394_state_t *sp, scsa1394_cmd_t *cmd)
14740Sstevel@tonic-gate {
14750Sstevel@tonic-gate struct scsi_pkt *pkt = cmd->sc_pkt;
14760Sstevel@tonic-gate
14770Sstevel@tonic-gate if (cmd->sc_flags & SCSA1394_CMD_CDB_EXT) {
14780Sstevel@tonic-gate kmem_free(pkt->pkt_cdbp, cmd->sc_cdb_len);
14790Sstevel@tonic-gate }
14800Sstevel@tonic-gate if (cmd->sc_flags & SCSA1394_CMD_SCB_EXT) {
14810Sstevel@tonic-gate kmem_free(pkt->pkt_scbp, cmd->sc_scb_len);
14820Sstevel@tonic-gate }
14830Sstevel@tonic-gate if (cmd->sc_flags & SCSA1394_CMD_PRIV_EXT) {
14840Sstevel@tonic-gate kmem_free(pkt->pkt_private, cmd->sc_priv_len);
14850Sstevel@tonic-gate }
14860Sstevel@tonic-gate cmd->sc_flags &= ~SCSA1394_CMD_EXT;
14870Sstevel@tonic-gate }
14880Sstevel@tonic-gate
14890Sstevel@tonic-gate /*ARGSUSED*/
14900Sstevel@tonic-gate static int
scsa1394_cmd_cdb_dma_alloc(scsa1394_state_t * sp,scsa1394_cmd_t * cmd,int flags,int (* callback)(),caddr_t arg)14910Sstevel@tonic-gate scsa1394_cmd_cdb_dma_alloc(scsa1394_state_t *sp, scsa1394_cmd_t *cmd,
14920Sstevel@tonic-gate int flags, int (*callback)(), caddr_t arg)
14930Sstevel@tonic-gate {
14940Sstevel@tonic-gate if (sbp2_task_orb_alloc(cmd->sc_lun->l_lun, &cmd->sc_task,
14950Sstevel@tonic-gate sizeof (scsa1394_cmd_orb_t)) != SBP2_SUCCESS) {
14960Sstevel@tonic-gate return (DDI_FAILURE);
14970Sstevel@tonic-gate }
14980Sstevel@tonic-gate
14990Sstevel@tonic-gate cmd->sc_flags |= SCSA1394_CMD_DMA_CDB_VALID;
15000Sstevel@tonic-gate return (DDI_SUCCESS);
15010Sstevel@tonic-gate }
15020Sstevel@tonic-gate
15030Sstevel@tonic-gate /*ARGSUSED*/
15040Sstevel@tonic-gate static void
scsa1394_cmd_cdb_dma_free(scsa1394_state_t * sp,scsa1394_cmd_t * cmd)15050Sstevel@tonic-gate scsa1394_cmd_cdb_dma_free(scsa1394_state_t *sp, scsa1394_cmd_t *cmd)
15060Sstevel@tonic-gate {
15070Sstevel@tonic-gate sbp2_task_orb_free(cmd->sc_lun->l_lun, &cmd->sc_task);
15080Sstevel@tonic-gate cmd->sc_flags &= ~SCSA1394_CMD_DMA_CDB_VALID;
15090Sstevel@tonic-gate }
15100Sstevel@tonic-gate
15110Sstevel@tonic-gate /*
15120Sstevel@tonic-gate * buffer resources
15130Sstevel@tonic-gate */
15140Sstevel@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)15150Sstevel@tonic-gate scsa1394_cmd_buf_dma_alloc(scsa1394_state_t *sp, scsa1394_cmd_t *cmd,
15160Sstevel@tonic-gate int flags, int (*callback)(), caddr_t arg, struct buf *bp)
15170Sstevel@tonic-gate {
15180Sstevel@tonic-gate scsa1394_lun_t *lp = cmd->sc_lun;
15190Sstevel@tonic-gate int kf = (callback == SLEEP_FUNC) ? KM_SLEEP : KM_NOSLEEP;
15200Sstevel@tonic-gate int dma_flags;
15210Sstevel@tonic-gate ddi_dma_cookie_t dmac;
15220Sstevel@tonic-gate uint_t ccount;
15230Sstevel@tonic-gate int error;
15240Sstevel@tonic-gate int ret;
15250Sstevel@tonic-gate
15260Sstevel@tonic-gate cmd->sc_bp = bp;
15270Sstevel@tonic-gate
15280Sstevel@tonic-gate if ((ddi_dma_alloc_handle(sp->s_dip, &sp->s_buf_dma_attr, callback,
15290Sstevel@tonic-gate NULL, &cmd->sc_buf_dma_hdl)) != DDI_SUCCESS) {
15300Sstevel@tonic-gate bioerror(bp, 0);
15310Sstevel@tonic-gate return (DDI_FAILURE);
15320Sstevel@tonic-gate }
15330Sstevel@tonic-gate
15340Sstevel@tonic-gate cmd->sc_flags &= ~SCSA1394_CMD_RDWR;
15350Sstevel@tonic-gate if (bp->b_flags & B_READ) {
15360Sstevel@tonic-gate dma_flags = DDI_DMA_READ;
15370Sstevel@tonic-gate cmd->sc_flags |= SCSA1394_CMD_READ;
15380Sstevel@tonic-gate } else {
15390Sstevel@tonic-gate dma_flags = DDI_DMA_WRITE;
15400Sstevel@tonic-gate cmd->sc_flags |= SCSA1394_CMD_WRITE;
15410Sstevel@tonic-gate }
15420Sstevel@tonic-gate if (flags & PKT_CONSISTENT) {
15430Sstevel@tonic-gate dma_flags |= DDI_DMA_CONSISTENT;
15440Sstevel@tonic-gate }
15450Sstevel@tonic-gate if (flags & PKT_DMA_PARTIAL) {
15460Sstevel@tonic-gate dma_flags |= DDI_DMA_PARTIAL;
15470Sstevel@tonic-gate }
15480Sstevel@tonic-gate
15490Sstevel@tonic-gate ret = ddi_dma_buf_bind_handle(cmd->sc_buf_dma_hdl, bp, dma_flags,
15500Sstevel@tonic-gate callback, arg, &dmac, &ccount);
15510Sstevel@tonic-gate
15520Sstevel@tonic-gate switch (ret) {
15530Sstevel@tonic-gate case DDI_DMA_MAPPED:
15540Sstevel@tonic-gate cmd->sc_nwin = 1;
15550Sstevel@tonic-gate cmd->sc_curwin = 0;
15560Sstevel@tonic-gate cmd->sc_win_offset = 0;
15570Sstevel@tonic-gate cmd->sc_win_len = bp->b_bcount;
15580Sstevel@tonic-gate break;
15590Sstevel@tonic-gate
15600Sstevel@tonic-gate case DDI_DMA_PARTIAL_MAP:
15610Sstevel@tonic-gate /* retrieve number of windows and first window cookie */
15620Sstevel@tonic-gate cmd->sc_curwin = 0;
15630Sstevel@tonic-gate if ((ddi_dma_numwin(cmd->sc_buf_dma_hdl, &cmd->sc_nwin) !=
15640Sstevel@tonic-gate DDI_SUCCESS) ||
15650Sstevel@tonic-gate (ddi_dma_getwin(cmd->sc_buf_dma_hdl, cmd->sc_curwin,
15660Sstevel@tonic-gate &cmd->sc_win_offset, &cmd->sc_win_len, &dmac, &ccount) !=
15670Sstevel@tonic-gate DDI_SUCCESS)) {
15680Sstevel@tonic-gate (void) ddi_dma_unbind_handle(cmd->sc_buf_dma_hdl);
15690Sstevel@tonic-gate ddi_dma_free_handle(&cmd->sc_buf_dma_hdl);
15700Sstevel@tonic-gate return (DDI_FAILURE);
15710Sstevel@tonic-gate }
1572276Sartem lp->l_stat.stat_cmd_buf_dma_partial++;
15730Sstevel@tonic-gate break;
15740Sstevel@tonic-gate
15750Sstevel@tonic-gate case DDI_DMA_NORESOURCES:
15760Sstevel@tonic-gate error = 0;
15770Sstevel@tonic-gate goto map_error;
15780Sstevel@tonic-gate
15790Sstevel@tonic-gate case DDI_DMA_BADATTR:
15800Sstevel@tonic-gate case DDI_DMA_NOMAPPING:
15810Sstevel@tonic-gate error = EFAULT;
15820Sstevel@tonic-gate goto map_error;
15830Sstevel@tonic-gate
15840Sstevel@tonic-gate default:
15850Sstevel@tonic-gate error = EINVAL;
15860Sstevel@tonic-gate
15870Sstevel@tonic-gate map_error:
15880Sstevel@tonic-gate bioerror(bp, error);
15890Sstevel@tonic-gate lp->l_stat.stat_err_cmd_buf_dbind++;
15900Sstevel@tonic-gate ddi_dma_free_handle(&cmd->sc_buf_dma_hdl);
15910Sstevel@tonic-gate return (DDI_FAILURE);
15920Sstevel@tonic-gate }
15930Sstevel@tonic-gate cmd->sc_flags |= SCSA1394_CMD_DMA_BUF_BIND_VALID;
15940Sstevel@tonic-gate
15950Sstevel@tonic-gate /*
15960Sstevel@tonic-gate * setup page table if needed
15970Sstevel@tonic-gate */
15980Sstevel@tonic-gate if ((ccount == 1) && (dmac.dmac_size <= SBP2_PT_SEGSIZE_MAX) &&
15990Sstevel@tonic-gate (!sp->s_symbios ||
16000Sstevel@tonic-gate (dmac.dmac_size <= scsa1394_symbios_page_size))) {
16010Sstevel@tonic-gate cmd->sc_buf_nsegs = 1;
16020Sstevel@tonic-gate cmd->sc_buf_seg_mem.ss_len = dmac.dmac_size;
16030Sstevel@tonic-gate cmd->sc_buf_seg_mem.ss_daddr = dmac.dmac_address;
16040Sstevel@tonic-gate cmd->sc_buf_seg = &cmd->sc_buf_seg_mem;
16050Sstevel@tonic-gate } else {
16060Sstevel@tonic-gate /* break window into segments */
16070Sstevel@tonic-gate if (scsa1394_cmd_dmac2seg(sp, cmd, &dmac, ccount, kf) !=
16080Sstevel@tonic-gate DDI_SUCCESS) {
16090Sstevel@tonic-gate scsa1394_cmd_buf_dma_free(sp, cmd);
16100Sstevel@tonic-gate bioerror(bp, 0);
16110Sstevel@tonic-gate return (DDI_FAILURE);
16120Sstevel@tonic-gate }
16130Sstevel@tonic-gate
16140Sstevel@tonic-gate /* allocate DMA resources for page table */
16150Sstevel@tonic-gate if (scsa1394_cmd_pt_dma_alloc(sp, cmd, callback, arg,
16160Sstevel@tonic-gate cmd->sc_buf_nsegs) != DDI_SUCCESS) {
16170Sstevel@tonic-gate scsa1394_cmd_buf_dma_free(sp, cmd);
16180Sstevel@tonic-gate bioerror(bp, 0);
16190Sstevel@tonic-gate return (DDI_FAILURE);
16200Sstevel@tonic-gate }
16210Sstevel@tonic-gate }
16220Sstevel@tonic-gate
16230Sstevel@tonic-gate /* allocate 1394 addresses for segments */
16240Sstevel@tonic-gate if (scsa1394_cmd_buf_addr_alloc(sp, cmd) != DDI_SUCCESS) {
16250Sstevel@tonic-gate scsa1394_cmd_buf_dma_free(sp, cmd);
16260Sstevel@tonic-gate bioerror(bp, 0);
16270Sstevel@tonic-gate return (DDI_FAILURE);
16280Sstevel@tonic-gate }
16290Sstevel@tonic-gate
16300Sstevel@tonic-gate return (DDI_SUCCESS);
16310Sstevel@tonic-gate }
16320Sstevel@tonic-gate
16330Sstevel@tonic-gate static void
scsa1394_cmd_buf_dma_free(scsa1394_state_t * sp,scsa1394_cmd_t * cmd)16340Sstevel@tonic-gate scsa1394_cmd_buf_dma_free(scsa1394_state_t *sp, scsa1394_cmd_t *cmd)
16350Sstevel@tonic-gate {
16360Sstevel@tonic-gate scsa1394_cmd_buf_addr_free(sp, cmd);
16370Sstevel@tonic-gate if (cmd->sc_flags & SCSA1394_CMD_DMA_BUF_PT_VALID) {
16380Sstevel@tonic-gate scsa1394_cmd_pt_dma_free(sp, cmd);
16390Sstevel@tonic-gate }
16400Sstevel@tonic-gate scsa1394_cmd_seg_free(sp, cmd);
16410Sstevel@tonic-gate if (cmd->sc_flags & SCSA1394_CMD_DMA_BUF_BIND_VALID) {
16420Sstevel@tonic-gate (void) ddi_dma_unbind_handle(cmd->sc_buf_dma_hdl);
16430Sstevel@tonic-gate ddi_dma_free_handle(&cmd->sc_buf_dma_hdl);
16440Sstevel@tonic-gate }
16450Sstevel@tonic-gate cmd->sc_flags &= ~(SCSA1394_CMD_DMA_BUF_VALID | SCSA1394_CMD_RDWR);
16460Sstevel@tonic-gate }
16470Sstevel@tonic-gate
16480Sstevel@tonic-gate /*
16490Sstevel@tonic-gate * Break a set DMA cookies into segments suitable for SBP-2 page table.
16500Sstevel@tonic-gate * This routine can reuse/reallocate segment array from previous calls.
16510Sstevel@tonic-gate */
16520Sstevel@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)16530Sstevel@tonic-gate scsa1394_cmd_dmac2seg(scsa1394_state_t *sp, scsa1394_cmd_t *cmd,
16540Sstevel@tonic-gate ddi_dma_cookie_t *dmac, uint_t ccount, int kf)
16550Sstevel@tonic-gate {
16560Sstevel@tonic-gate scsa1394_lun_t *lp = cmd->sc_lun;
16570Sstevel@tonic-gate int i;
16580Sstevel@tonic-gate int nsegs;
16590Sstevel@tonic-gate size_t segsize_max;
16600Sstevel@tonic-gate size_t dmac_resid;
16610Sstevel@tonic-gate uint32_t dmac_addr;
16620Sstevel@tonic-gate scsa1394_cmd_seg_t *seg;
16630Sstevel@tonic-gate
16640Sstevel@tonic-gate if (!sp->s_symbios) {
16650Sstevel@tonic-gate /*
16660Sstevel@tonic-gate * Number of segments is unknown at this point. Start with
16670Sstevel@tonic-gate * a reasonable estimate and grow it later if needed.
16680Sstevel@tonic-gate */
16690Sstevel@tonic-gate nsegs = max(ccount, cmd->sc_win_len / SBP2_PT_SEGSIZE_MAX) * 2;
16700Sstevel@tonic-gate segsize_max = SBP2_PT_SEGSIZE_MAX;
16710Sstevel@tonic-gate } else {
1672276Sartem /*
1673276Sartem * For Symbios workaround we know exactly the number of segments
1674276Sartem * Additional segment may be needed if buffer is not aligned.
1675276Sartem */
1676276Sartem nsegs =
1677276Sartem howmany(cmd->sc_win_len, scsa1394_symbios_page_size) + 1;
16780Sstevel@tonic-gate segsize_max = scsa1394_symbios_page_size;
16790Sstevel@tonic-gate }
16800Sstevel@tonic-gate
16810Sstevel@tonic-gate if (nsegs > cmd->sc_buf_nsegs_alloc) {
16820Sstevel@tonic-gate if ((cmd->sc_buf_seg = scsa1394_kmem_realloc(cmd->sc_buf_seg,
16830Sstevel@tonic-gate cmd->sc_buf_nsegs_alloc, nsegs,
16840Sstevel@tonic-gate sizeof (scsa1394_cmd_seg_t), kf)) == NULL) {
16850Sstevel@tonic-gate cmd->sc_buf_nsegs_alloc = 0;
16860Sstevel@tonic-gate return (DDI_FAILURE);
16870Sstevel@tonic-gate }
16880Sstevel@tonic-gate cmd->sc_buf_nsegs_alloc = nsegs;
16890Sstevel@tonic-gate }
16900Sstevel@tonic-gate
16910Sstevel@tonic-gate /* each cookie maps into one or more segments */
16920Sstevel@tonic-gate cmd->sc_buf_nsegs = 0;
16930Sstevel@tonic-gate i = ccount;
16940Sstevel@tonic-gate for (;;) {
16950Sstevel@tonic-gate dmac_resid = dmac->dmac_size;
16960Sstevel@tonic-gate dmac_addr = dmac->dmac_address;
16970Sstevel@tonic-gate while (dmac_resid > 0) {
16980Sstevel@tonic-gate /* grow array if needed */
16990Sstevel@tonic-gate if (cmd->sc_buf_nsegs >= cmd->sc_buf_nsegs_alloc) {
17000Sstevel@tonic-gate if ((cmd->sc_buf_seg = scsa1394_kmem_realloc(
17010Sstevel@tonic-gate cmd->sc_buf_seg,
17020Sstevel@tonic-gate cmd->sc_buf_nsegs_alloc,
17030Sstevel@tonic-gate cmd->sc_buf_nsegs_alloc + ccount,
17040Sstevel@tonic-gate sizeof (scsa1394_cmd_seg_t), kf)) == NULL) {
17050Sstevel@tonic-gate return (DDI_FAILURE);
17060Sstevel@tonic-gate }
17070Sstevel@tonic-gate cmd->sc_buf_nsegs_alloc += ccount;
17080Sstevel@tonic-gate }
17090Sstevel@tonic-gate
17100Sstevel@tonic-gate seg = &cmd->sc_buf_seg[cmd->sc_buf_nsegs];
17110Sstevel@tonic-gate seg->ss_len = min(dmac_resid, segsize_max);
17120Sstevel@tonic-gate seg->ss_daddr = (uint64_t)dmac_addr;
17130Sstevel@tonic-gate dmac_addr += seg->ss_len;
17140Sstevel@tonic-gate dmac_resid -= seg->ss_len;
17150Sstevel@tonic-gate cmd->sc_buf_nsegs++;
17160Sstevel@tonic-gate }
17170Sstevel@tonic-gate ASSERT(dmac_resid == 0);
17180Sstevel@tonic-gate
17190Sstevel@tonic-gate /* grab next cookie */
17200Sstevel@tonic-gate if (--i <= 0) {
17210Sstevel@tonic-gate break;
17220Sstevel@tonic-gate }
17230Sstevel@tonic-gate ddi_dma_nextcookie(cmd->sc_buf_dma_hdl, dmac);
17240Sstevel@tonic-gate }
17250Sstevel@tonic-gate
17260Sstevel@tonic-gate if (cmd->sc_buf_nsegs > lp->l_stat.stat_cmd_buf_max_nsegs) {
17270Sstevel@tonic-gate lp->l_stat.stat_cmd_buf_max_nsegs = cmd->sc_buf_nsegs;
17280Sstevel@tonic-gate }
17290Sstevel@tonic-gate
17300Sstevel@tonic-gate return (DDI_SUCCESS);
17310Sstevel@tonic-gate }
17320Sstevel@tonic-gate
17330Sstevel@tonic-gate /*ARGSUSED*/
17340Sstevel@tonic-gate static void
scsa1394_cmd_seg_free(scsa1394_state_t * sp,scsa1394_cmd_t * cmd)17350Sstevel@tonic-gate scsa1394_cmd_seg_free(scsa1394_state_t *sp, scsa1394_cmd_t *cmd)
17360Sstevel@tonic-gate {
17370Sstevel@tonic-gate if (cmd->sc_buf_nsegs_alloc > 0) {
17380Sstevel@tonic-gate kmem_free(cmd->sc_buf_seg, cmd->sc_buf_nsegs_alloc *
17390Sstevel@tonic-gate sizeof (scsa1394_cmd_seg_t));
17400Sstevel@tonic-gate }
17410Sstevel@tonic-gate cmd->sc_buf_seg = NULL;
17420Sstevel@tonic-gate cmd->sc_buf_nsegs = 0;
17430Sstevel@tonic-gate cmd->sc_buf_nsegs_alloc = 0;
17440Sstevel@tonic-gate }
17450Sstevel@tonic-gate
17460Sstevel@tonic-gate static int
scsa1394_cmd_pt_dma_alloc(scsa1394_state_t * sp,scsa1394_cmd_t * cmd,int (* callback)(),caddr_t arg,int cnt)17470Sstevel@tonic-gate scsa1394_cmd_pt_dma_alloc(scsa1394_state_t *sp, scsa1394_cmd_t *cmd,
17480Sstevel@tonic-gate int (*callback)(), caddr_t arg, int cnt)
17490Sstevel@tonic-gate {
17500Sstevel@tonic-gate scsa1394_lun_t *lp = cmd->sc_lun;
17510Sstevel@tonic-gate size_t len, rlen;
17520Sstevel@tonic-gate uint_t ccount;
17530Sstevel@tonic-gate t1394_alloc_addr_t aa;
17540Sstevel@tonic-gate int result;
17550Sstevel@tonic-gate
17560Sstevel@tonic-gate /* allocate DMA memory for page table */
17570Sstevel@tonic-gate if ((ddi_dma_alloc_handle(sp->s_dip, &sp->s_pt_dma_attr,
17580Sstevel@tonic-gate callback, NULL, &cmd->sc_pt_dma_hdl)) != DDI_SUCCESS) {
17590Sstevel@tonic-gate lp->l_stat.stat_err_cmd_pt_dmem_alloc++;
17600Sstevel@tonic-gate return (DDI_FAILURE);
17610Sstevel@tonic-gate }
17620Sstevel@tonic-gate
17630Sstevel@tonic-gate cmd->sc_pt_ent_alloc = cnt;
17640Sstevel@tonic-gate len = cmd->sc_pt_ent_alloc * SBP2_PT_ENT_SIZE;
17650Sstevel@tonic-gate if (ddi_dma_mem_alloc(cmd->sc_pt_dma_hdl, len,
17660Sstevel@tonic-gate &sp->s_attachinfo.acc_attr, DDI_DMA_CONSISTENT, callback, arg,
17670Sstevel@tonic-gate &cmd->sc_pt_kaddr, &rlen, &cmd->sc_pt_acc_hdl) != DDI_SUCCESS) {
17680Sstevel@tonic-gate ddi_dma_free_handle(&cmd->sc_pt_dma_hdl);
17690Sstevel@tonic-gate lp->l_stat.stat_err_cmd_pt_dmem_alloc++;
17700Sstevel@tonic-gate return (DDI_FAILURE);
17710Sstevel@tonic-gate }
17720Sstevel@tonic-gate
17730Sstevel@tonic-gate if (ddi_dma_addr_bind_handle(cmd->sc_pt_dma_hdl, NULL,
17740Sstevel@tonic-gate cmd->sc_pt_kaddr, len, DDI_DMA_READ | DDI_DMA_CONSISTENT,
17750Sstevel@tonic-gate callback, arg, &cmd->sc_pt_dmac, &ccount) != DDI_DMA_MAPPED) {
17760Sstevel@tonic-gate ddi_dma_mem_free(&cmd->sc_pt_acc_hdl);
17770Sstevel@tonic-gate ddi_dma_free_handle(&cmd->sc_pt_dma_hdl);
17780Sstevel@tonic-gate lp->l_stat.stat_err_cmd_pt_dmem_alloc++;
17790Sstevel@tonic-gate return (DDI_FAILURE);
17800Sstevel@tonic-gate }
17810Sstevel@tonic-gate ASSERT(ccount == 1); /* because dma_attr_sgllen is 1 */
17820Sstevel@tonic-gate
17830Sstevel@tonic-gate /* allocate 1394 address for page table */
17840Sstevel@tonic-gate aa.aa_type = T1394_ADDR_FIXED;
17850Sstevel@tonic-gate aa.aa_length = len;
17860Sstevel@tonic-gate aa.aa_address = cmd->sc_pt_dmac.dmac_address;
17870Sstevel@tonic-gate aa.aa_evts.recv_read_request = NULL;
17880Sstevel@tonic-gate aa.aa_evts.recv_write_request = NULL;
17890Sstevel@tonic-gate aa.aa_evts.recv_lock_request = NULL;
17900Sstevel@tonic-gate aa.aa_arg = NULL;
17910Sstevel@tonic-gate aa.aa_kmem_bufp = NULL;
17920Sstevel@tonic-gate aa.aa_enable = T1394_ADDR_RDENBL;
17930Sstevel@tonic-gate if (t1394_alloc_addr(sp->s_t1394_hdl, &aa, 0, &result) != DDI_SUCCESS) {
17940Sstevel@tonic-gate (void) ddi_dma_unbind_handle(cmd->sc_pt_dma_hdl);
17950Sstevel@tonic-gate ddi_dma_mem_free(&cmd->sc_pt_acc_hdl);
17960Sstevel@tonic-gate ddi_dma_free_handle(&cmd->sc_pt_dma_hdl);
17970Sstevel@tonic-gate lp->l_stat.stat_err_cmd_pt_addr_alloc++;
17980Sstevel@tonic-gate return (DDI_FAILURE);
17990Sstevel@tonic-gate }
18000Sstevel@tonic-gate ASSERT(aa.aa_address != 0);
18010Sstevel@tonic-gate cmd->sc_pt_baddr = aa.aa_address;
18020Sstevel@tonic-gate cmd->sc_pt_addr_hdl = aa.aa_hdl;
18030Sstevel@tonic-gate
18040Sstevel@tonic-gate cmd->sc_flags |= SCSA1394_CMD_DMA_BUF_PT_VALID;
18050Sstevel@tonic-gate
18060Sstevel@tonic-gate return (DDI_SUCCESS);
18070Sstevel@tonic-gate }
18080Sstevel@tonic-gate
18090Sstevel@tonic-gate static void
scsa1394_cmd_pt_dma_free(scsa1394_state_t * sp,scsa1394_cmd_t * cmd)18100Sstevel@tonic-gate scsa1394_cmd_pt_dma_free(scsa1394_state_t *sp, scsa1394_cmd_t *cmd)
18110Sstevel@tonic-gate {
18120Sstevel@tonic-gate (void) ddi_dma_unbind_handle(cmd->sc_pt_dma_hdl);
18130Sstevel@tonic-gate ddi_dma_mem_free(&cmd->sc_pt_acc_hdl);
18140Sstevel@tonic-gate ddi_dma_free_handle(&cmd->sc_pt_dma_hdl);
18150Sstevel@tonic-gate (void) t1394_free_addr(sp->s_t1394_hdl, &cmd->sc_pt_addr_hdl, 0);
18160Sstevel@tonic-gate cmd->sc_flags &= ~SCSA1394_CMD_DMA_BUF_PT_VALID;
18170Sstevel@tonic-gate }
18180Sstevel@tonic-gate
18190Sstevel@tonic-gate /*
18200Sstevel@tonic-gate * allocate 1394 addresses for all buffer segments
18210Sstevel@tonic-gate */
18220Sstevel@tonic-gate static int
scsa1394_cmd_buf_addr_alloc(scsa1394_state_t * sp,scsa1394_cmd_t * cmd)18230Sstevel@tonic-gate scsa1394_cmd_buf_addr_alloc(scsa1394_state_t *sp, scsa1394_cmd_t *cmd)
18240Sstevel@tonic-gate {
18250Sstevel@tonic-gate scsa1394_lun_t *lp = cmd->sc_lun;
18260Sstevel@tonic-gate t1394_alloc_addr_t aa;
18270Sstevel@tonic-gate scsa1394_cmd_seg_t *seg;
18280Sstevel@tonic-gate int result;
18290Sstevel@tonic-gate int i;
18300Sstevel@tonic-gate
18310Sstevel@tonic-gate aa.aa_type = T1394_ADDR_FIXED;
18320Sstevel@tonic-gate aa.aa_evts.recv_read_request = NULL;
18330Sstevel@tonic-gate aa.aa_evts.recv_write_request = NULL;
18340Sstevel@tonic-gate aa.aa_evts.recv_lock_request = NULL;
18350Sstevel@tonic-gate aa.aa_arg = NULL;
18360Sstevel@tonic-gate aa.aa_kmem_bufp = NULL;
18370Sstevel@tonic-gate if (cmd->sc_flags & SCSA1394_CMD_READ) {
18380Sstevel@tonic-gate aa.aa_enable = T1394_ADDR_RDENBL;
18390Sstevel@tonic-gate } else {
18400Sstevel@tonic-gate aa.aa_enable = T1394_ADDR_WRENBL;
18410Sstevel@tonic-gate }
18420Sstevel@tonic-gate
18430Sstevel@tonic-gate for (i = 0; i < cmd->sc_buf_nsegs; i++) {
18440Sstevel@tonic-gate seg = &cmd->sc_buf_seg[i];
18450Sstevel@tonic-gate
18460Sstevel@tonic-gate /* segment bus address */
18470Sstevel@tonic-gate aa.aa_length = seg->ss_len;
18480Sstevel@tonic-gate aa.aa_address = seg->ss_daddr;
18490Sstevel@tonic-gate
18500Sstevel@tonic-gate if (t1394_alloc_addr(sp->s_t1394_hdl, &aa, 0, &result) !=
18510Sstevel@tonic-gate DDI_SUCCESS) {
18520Sstevel@tonic-gate lp->l_stat.stat_err_cmd_buf_addr_alloc++;
18530Sstevel@tonic-gate return (DDI_FAILURE);
18540Sstevel@tonic-gate }
18550Sstevel@tonic-gate ASSERT(aa.aa_address != 0);
18560Sstevel@tonic-gate seg->ss_baddr = aa.aa_address;
18570Sstevel@tonic-gate seg->ss_addr_hdl = aa.aa_hdl;
18580Sstevel@tonic-gate }
18590Sstevel@tonic-gate
18600Sstevel@tonic-gate cmd->sc_flags |= SCSA1394_CMD_DMA_BUF_ADDR_VALID;
18610Sstevel@tonic-gate
18620Sstevel@tonic-gate return (DDI_SUCCESS);
18630Sstevel@tonic-gate }
18640Sstevel@tonic-gate
18650Sstevel@tonic-gate static void
scsa1394_cmd_buf_addr_free(scsa1394_state_t * sp,scsa1394_cmd_t * cmd)18660Sstevel@tonic-gate scsa1394_cmd_buf_addr_free(scsa1394_state_t *sp, scsa1394_cmd_t *cmd)
18670Sstevel@tonic-gate {
18680Sstevel@tonic-gate int i;
18690Sstevel@tonic-gate
18700Sstevel@tonic-gate for (i = 0; i < cmd->sc_buf_nsegs; i++) {
18710Sstevel@tonic-gate if (cmd->sc_buf_seg[i].ss_addr_hdl) {
18720Sstevel@tonic-gate (void) t1394_free_addr(sp->s_t1394_hdl,
18730Sstevel@tonic-gate &cmd->sc_buf_seg[i].ss_addr_hdl, 0);
18740Sstevel@tonic-gate }
18750Sstevel@tonic-gate }
18760Sstevel@tonic-gate cmd->sc_flags &= ~SCSA1394_CMD_DMA_BUF_ADDR_VALID;
18770Sstevel@tonic-gate }
18780Sstevel@tonic-gate
18790Sstevel@tonic-gate /*
18800Sstevel@tonic-gate * move to next DMA window
18810Sstevel@tonic-gate */
18820Sstevel@tonic-gate static int
scsa1394_cmd_buf_dma_move(scsa1394_state_t * sp,scsa1394_cmd_t * cmd)18830Sstevel@tonic-gate scsa1394_cmd_buf_dma_move(scsa1394_state_t *sp, scsa1394_cmd_t *cmd)
18840Sstevel@tonic-gate {
18850Sstevel@tonic-gate /* scsa1394_lun_t *lp = cmd->sc_lun; */
18860Sstevel@tonic-gate ddi_dma_cookie_t dmac;
18870Sstevel@tonic-gate uint_t ccount;
18880Sstevel@tonic-gate
18890Sstevel@tonic-gate /* for small pkts, leave things where they are (says WDD) */
18900Sstevel@tonic-gate if ((cmd->sc_curwin == cmd->sc_nwin) && (cmd->sc_nwin == 1)) {
18910Sstevel@tonic-gate return (DDI_SUCCESS);
18920Sstevel@tonic-gate }
18930Sstevel@tonic-gate if (++cmd->sc_curwin >= cmd->sc_nwin) {
18940Sstevel@tonic-gate return (DDI_FAILURE);
18950Sstevel@tonic-gate }
18960Sstevel@tonic-gate if (ddi_dma_getwin(cmd->sc_buf_dma_hdl, cmd->sc_curwin,
18970Sstevel@tonic-gate &cmd->sc_win_offset, &cmd->sc_win_len, &dmac, &ccount) !=
18980Sstevel@tonic-gate DDI_SUCCESS) {
18990Sstevel@tonic-gate return (DDI_FAILURE);
19000Sstevel@tonic-gate }
19010Sstevel@tonic-gate
19020Sstevel@tonic-gate scsa1394_cmd_buf_addr_free(sp, cmd);
19030Sstevel@tonic-gate
19040Sstevel@tonic-gate /*
19050Sstevel@tonic-gate * setup page table if needed
19060Sstevel@tonic-gate */
1907276Sartem if ((ccount == 1) && (dmac.dmac_size <= SBP2_PT_SEGSIZE_MAX) &&
1908276Sartem (!sp->s_symbios ||
1909276Sartem (dmac.dmac_size <= scsa1394_symbios_page_size))) {
19100Sstevel@tonic-gate /* but first, free old resources */
19110Sstevel@tonic-gate if (cmd->sc_flags & SCSA1394_CMD_DMA_BUF_PT_VALID) {
19120Sstevel@tonic-gate scsa1394_cmd_pt_dma_free(sp, cmd);
19130Sstevel@tonic-gate }
19140Sstevel@tonic-gate scsa1394_cmd_seg_free(sp, cmd);
19150Sstevel@tonic-gate
19160Sstevel@tonic-gate cmd->sc_buf_nsegs = 1;
19170Sstevel@tonic-gate cmd->sc_buf_seg_mem.ss_len = dmac.dmac_size;
19180Sstevel@tonic-gate cmd->sc_buf_seg_mem.ss_daddr = dmac.dmac_address;
19190Sstevel@tonic-gate cmd->sc_buf_seg = &cmd->sc_buf_seg_mem;
19200Sstevel@tonic-gate } else {
19210Sstevel@tonic-gate /* break window into segments */
19220Sstevel@tonic-gate if (scsa1394_cmd_dmac2seg(sp, cmd, &dmac, ccount, KM_NOSLEEP) !=
19230Sstevel@tonic-gate DDI_SUCCESS) {
19240Sstevel@tonic-gate return (DDI_FAILURE);
19250Sstevel@tonic-gate }
19260Sstevel@tonic-gate
19270Sstevel@tonic-gate /* allocate DMA resources */
19280Sstevel@tonic-gate if (scsa1394_cmd_pt_dma_alloc(sp, cmd, NULL_FUNC, NULL,
19290Sstevel@tonic-gate cmd->sc_buf_nsegs) != DDI_SUCCESS) {
19300Sstevel@tonic-gate return (DDI_FAILURE);
19310Sstevel@tonic-gate }
19320Sstevel@tonic-gate }
19330Sstevel@tonic-gate
19340Sstevel@tonic-gate /* allocate 1394 addresses for segments */
19350Sstevel@tonic-gate if (scsa1394_cmd_buf_addr_alloc(sp, cmd) != DDI_SUCCESS) {
19360Sstevel@tonic-gate return (DDI_FAILURE);
19370Sstevel@tonic-gate }
19380Sstevel@tonic-gate
19390Sstevel@tonic-gate return (DDI_SUCCESS);
19400Sstevel@tonic-gate }
19410Sstevel@tonic-gate
19420Sstevel@tonic-gate /*
19430Sstevel@tonic-gate *
19440Sstevel@tonic-gate * --- pkt and data transfer routines
19450Sstevel@tonic-gate *
19460Sstevel@tonic-gate */
19470Sstevel@tonic-gate static int
scsa1394_scsi_start(struct scsi_address * ap,struct scsi_pkt * pkt)19480Sstevel@tonic-gate scsa1394_scsi_start(struct scsi_address *ap, struct scsi_pkt *pkt)
19490Sstevel@tonic-gate {
19500Sstevel@tonic-gate scsa1394_state_t *sp = ADDR2STATE(ap);
19510Sstevel@tonic-gate scsa1394_cmd_t *cmd = PKT2CMD(pkt);
19520Sstevel@tonic-gate scsa1394_lun_t *lp = cmd->sc_lun;
19530Sstevel@tonic-gate int ret;
19540Sstevel@tonic-gate
19550Sstevel@tonic-gate /*
19560Sstevel@tonic-gate * since we don't support polled I/O, just accept the packet
19570Sstevel@tonic-gate * so the rest of the file systems get synced properly
19580Sstevel@tonic-gate */
19590Sstevel@tonic-gate if (ddi_in_panic()) {
19600Sstevel@tonic-gate scsa1394_prepare_pkt(sp, pkt);
19610Sstevel@tonic-gate return (TRAN_ACCEPT);
19620Sstevel@tonic-gate }
19630Sstevel@tonic-gate
19640Sstevel@tonic-gate /* polling not supported yet */
19650Sstevel@tonic-gate if (pkt->pkt_flags & FLAG_NOINTR) {
19660Sstevel@tonic-gate return (TRAN_BADPKT);
19670Sstevel@tonic-gate }
19680Sstevel@tonic-gate
1969276Sartem mutex_enter(&sp->s_mutex);
1970276Sartem if (sp->s_dev_state != SCSA1394_DEV_ONLINE) {
1971276Sartem /*
1972276Sartem * If device is temporarily gone due to bus reset,
1973276Sartem * return busy to prevent prevent scary console messages.
1974276Sartem * If permanently gone, leave it to scsa1394_cmd_fake_comp().
1975276Sartem */
1976276Sartem if (sp->s_dev_state == SCSA1394_DEV_BUS_RESET) {
1977276Sartem mutex_exit(&sp->s_mutex);
1978276Sartem return (TRAN_BUSY);
1979276Sartem }
1980276Sartem }
1981276Sartem mutex_exit(&sp->s_mutex);
1982276Sartem
19830Sstevel@tonic-gate if ((ap->a_lun >= sp->s_nluns) ||
19840Sstevel@tonic-gate (ap->a_lun != pkt->pkt_address.a_lun)) {
19850Sstevel@tonic-gate return (TRAN_BADPKT);
19860Sstevel@tonic-gate }
19870Sstevel@tonic-gate
19880Sstevel@tonic-gate scsa1394_prepare_pkt(sp, pkt);
19890Sstevel@tonic-gate
19900Sstevel@tonic-gate /* some commands may require fake completion */
19910Sstevel@tonic-gate if ((ret = scsa1394_cmd_fake_comp(sp, cmd)) == DDI_SUCCESS) {
19920Sstevel@tonic-gate return (TRAN_ACCEPT);
19930Sstevel@tonic-gate }
19940Sstevel@tonic-gate
19950Sstevel@tonic-gate scsa1394_cmd_fill_cdb(lp, cmd);
19960Sstevel@tonic-gate
19970Sstevel@tonic-gate if (cmd->sc_flags & SCSA1394_CMD_DMA_BUF_PT_VALID) {
19980Sstevel@tonic-gate scsa1394_sbp2_seg2pt(lp, cmd);
19990Sstevel@tonic-gate }
20000Sstevel@tonic-gate
20010Sstevel@tonic-gate scsa1394_sbp2_cmd2orb(lp, cmd); /* convert into ORB */
20020Sstevel@tonic-gate
20038763SAlan.Perry@Sun.COM if ((ret = scsa1394_sbp2_start(lp, cmd)) != TRAN_BUSY) {
20040Sstevel@tonic-gate scsa1394_sbp2_nudge(lp);
20050Sstevel@tonic-gate }
20060Sstevel@tonic-gate
20070Sstevel@tonic-gate return (ret);
20080Sstevel@tonic-gate }
20090Sstevel@tonic-gate
20100Sstevel@tonic-gate /*ARGSUSED*/
20110Sstevel@tonic-gate static void
scsa1394_prepare_pkt(scsa1394_state_t * sp,struct scsi_pkt * pkt)20120Sstevel@tonic-gate scsa1394_prepare_pkt(scsa1394_state_t *sp, struct scsi_pkt *pkt)
20130Sstevel@tonic-gate {
20140Sstevel@tonic-gate scsa1394_cmd_t *cmd = PKT2CMD(pkt);
20150Sstevel@tonic-gate
20160Sstevel@tonic-gate pkt->pkt_reason = CMD_CMPLT;
20170Sstevel@tonic-gate pkt->pkt_state = 0;
20180Sstevel@tonic-gate pkt->pkt_statistics = 0;
20190Sstevel@tonic-gate *(pkt->pkt_scbp) = STATUS_GOOD;
20200Sstevel@tonic-gate
20210Sstevel@tonic-gate if (cmd) {
20220Sstevel@tonic-gate cmd->sc_timeout = pkt->pkt_time;
20230Sstevel@tonic-gate
20240Sstevel@tonic-gate /* workarounds */
20250Sstevel@tonic-gate switch (pkt->pkt_cdbp[0]) {
20260Sstevel@tonic-gate /*
20270Sstevel@tonic-gate * sd does START_STOP_UNIT during attach with a 200 sec timeout.
20280Sstevel@tonic-gate * at this time devi_lock is held, prtconf will be stuck.
20290Sstevel@tonic-gate * reduce timeout for the time being.
20300Sstevel@tonic-gate */
20310Sstevel@tonic-gate case SCMD_START_STOP:
20320Sstevel@tonic-gate cmd->sc_timeout = min(cmd->sc_timeout,
20330Sstevel@tonic-gate scsa1394_start_stop_timeout_max);
20340Sstevel@tonic-gate break;
20350Sstevel@tonic-gate default:
20360Sstevel@tonic-gate break;
20370Sstevel@tonic-gate }
20380Sstevel@tonic-gate }
20390Sstevel@tonic-gate }
20400Sstevel@tonic-gate
20410Sstevel@tonic-gate static void
scsa1394_cmd_fill_cdb(scsa1394_lun_t * lp,scsa1394_cmd_t * cmd)20420Sstevel@tonic-gate scsa1394_cmd_fill_cdb(scsa1394_lun_t *lp, scsa1394_cmd_t *cmd)
20430Sstevel@tonic-gate {
20440Sstevel@tonic-gate cmd->sc_cdb_actual_len = cmd->sc_cdb_len;
20450Sstevel@tonic-gate
20460Sstevel@tonic-gate mutex_enter(&lp->l_mutex);
20470Sstevel@tonic-gate
20480Sstevel@tonic-gate switch (lp->l_dtype_orig) {
20490Sstevel@tonic-gate case DTYPE_DIRECT:
20500Sstevel@tonic-gate case DTYPE_RODIRECT:
20510Sstevel@tonic-gate case DTYPE_OPTICAL:
20520Sstevel@tonic-gate case SCSA1394_DTYPE_RBC:
20530Sstevel@tonic-gate scsa1394_cmd_fill_cdb_rbc(lp, cmd);
20540Sstevel@tonic-gate break;
20550Sstevel@tonic-gate default:
20560Sstevel@tonic-gate scsa1394_cmd_fill_cdb_other(lp, cmd);
20570Sstevel@tonic-gate break;
20580Sstevel@tonic-gate }
20590Sstevel@tonic-gate
20600Sstevel@tonic-gate mutex_exit(&lp->l_mutex);
20610Sstevel@tonic-gate }
20620Sstevel@tonic-gate
20630Sstevel@tonic-gate static void
scsa1394_cmd_fill_cdb_rbc(scsa1394_lun_t * lp,scsa1394_cmd_t * cmd)20640Sstevel@tonic-gate scsa1394_cmd_fill_cdb_rbc(scsa1394_lun_t *lp, scsa1394_cmd_t *cmd)
20650Sstevel@tonic-gate {
20660Sstevel@tonic-gate scsa1394_state_t *sp = lp->l_sp;
20670Sstevel@tonic-gate struct scsi_pkt *pkt = CMD2PKT(cmd);
20680Sstevel@tonic-gate int lba, opcode;
20690Sstevel@tonic-gate struct buf *bp = cmd->sc_bp;
20700Sstevel@tonic-gate size_t len;
20710Sstevel@tonic-gate size_t blk_size;
20720Sstevel@tonic-gate int sz;
20730Sstevel@tonic-gate
20740Sstevel@tonic-gate opcode = pkt->pkt_cdbp[0];
20750Sstevel@tonic-gate blk_size = lp->l_lba_size;
20760Sstevel@tonic-gate
20770Sstevel@tonic-gate switch (opcode) {
20780Sstevel@tonic-gate case SCMD_READ:
20790Sstevel@tonic-gate /* RBC only supports 10-byte read/write */
20800Sstevel@tonic-gate lba = SCSA1394_LBA_6BYTE(pkt);
20810Sstevel@tonic-gate len = SCSA1394_LEN_6BYTE(pkt);
20820Sstevel@tonic-gate opcode = SCMD_READ_G1;
20830Sstevel@tonic-gate cmd->sc_cdb_actual_len = CDB_GROUP1;
20840Sstevel@tonic-gate break;
20850Sstevel@tonic-gate case SCMD_WRITE:
20860Sstevel@tonic-gate lba = SCSA1394_LBA_6BYTE(pkt);
20870Sstevel@tonic-gate len = SCSA1394_LEN_6BYTE(pkt);
20880Sstevel@tonic-gate opcode = SCMD_WRITE_G1;
20890Sstevel@tonic-gate cmd->sc_cdb_actual_len = CDB_GROUP1;
20900Sstevel@tonic-gate break;
20910Sstevel@tonic-gate case SCMD_READ_G1:
20920Sstevel@tonic-gate case SCMD_READ_LONG:
20930Sstevel@tonic-gate lba = SCSA1394_LBA_10BYTE(pkt);
20940Sstevel@tonic-gate len = SCSA1394_LEN_10BYTE(pkt);
20950Sstevel@tonic-gate break;
20960Sstevel@tonic-gate case SCMD_WRITE_G1:
20970Sstevel@tonic-gate case SCMD_WRITE_LONG:
20980Sstevel@tonic-gate lba = SCSA1394_LBA_10BYTE(pkt);
20990Sstevel@tonic-gate len = SCSA1394_LEN_10BYTE(pkt);
2100276Sartem if ((lp->l_dtype_orig == DTYPE_RODIRECT) &&
2101276Sartem (bp != NULL) && (len != 0)) {
2102276Sartem sz = SCSA1394_CDRW_BLKSZ(bp->b_bcount, len);
2103276Sartem if (SCSA1394_VALID_CDRW_BLKSZ(sz)) {
2104276Sartem blk_size = sz;
2105276Sartem }
21060Sstevel@tonic-gate }
21070Sstevel@tonic-gate break;
21080Sstevel@tonic-gate case SCMD_READ_CD:
21090Sstevel@tonic-gate lba = SCSA1394_LBA_10BYTE(pkt);
21100Sstevel@tonic-gate len = SCSA1394_LEN_READ_CD(pkt);
21110Sstevel@tonic-gate blk_size = scsa1394_cmd_read_cd_blk_size(pkt->pkt_cdbp[1] >> 2);
21120Sstevel@tonic-gate break;
21130Sstevel@tonic-gate case SCMD_READ_G5:
21140Sstevel@tonic-gate lba = SCSA1394_LBA_12BYTE(pkt);
21150Sstevel@tonic-gate len = SCSA1394_LEN_12BYTE(pkt);
21160Sstevel@tonic-gate break;
21170Sstevel@tonic-gate case SCMD_WRITE_G5:
21180Sstevel@tonic-gate lba = SCSA1394_LBA_12BYTE(pkt);
21190Sstevel@tonic-gate len = SCSA1394_LEN_12BYTE(pkt);
21200Sstevel@tonic-gate break;
21210Sstevel@tonic-gate default:
21220Sstevel@tonic-gate /* no special mapping for other commands */
21230Sstevel@tonic-gate scsa1394_cmd_fill_cdb_other(lp, cmd);
21240Sstevel@tonic-gate return;
21250Sstevel@tonic-gate }
2126276Sartem cmd->sc_blk_size = blk_size;
21270Sstevel@tonic-gate
21280Sstevel@tonic-gate /* limit xfer length for Symbios workaround */
21290Sstevel@tonic-gate if (sp->s_symbios && (len * blk_size > scsa1394_symbios_size_max)) {
21300Sstevel@tonic-gate cmd->sc_flags |= SCSA1394_CMD_SYMBIOS_BREAKUP;
21310Sstevel@tonic-gate
21320Sstevel@tonic-gate cmd->sc_total_blks = cmd->sc_resid_blks = len;
21330Sstevel@tonic-gate
21340Sstevel@tonic-gate len = scsa1394_symbios_size_max / blk_size;
21350Sstevel@tonic-gate }
21360Sstevel@tonic-gate cmd->sc_xfer_blks = len;
21370Sstevel@tonic-gate cmd->sc_xfer_bytes = len * blk_size;
21380Sstevel@tonic-gate
21390Sstevel@tonic-gate /* finalize new CDB */
21401963Sap25164 switch (pkt->pkt_cdbp[0]) {
21411963Sap25164 case SCMD_READ:
21421963Sap25164 case SCMD_WRITE:
21431963Sap25164 /*
21441963Sap25164 * We rewrite READ/WRITE G0 commands as READ/WRITE G1.
21451963Sap25164 * Build new cdb from scatch.
21461963Sap25164 * The lba and length fields is updated below.
21471963Sap25164 */
21481963Sap25164 bzero(cmd->sc_cdb, cmd->sc_cdb_actual_len);
21491963Sap25164 break;
21501963Sap25164 default:
21511963Sap25164 /*
21521963Sap25164 * Copy the non lba/len fields.
21531963Sap25164 * The lba and length fields is updated below.
21541963Sap25164 */
21551963Sap25164 bcopy(pkt->pkt_cdbp, cmd->sc_cdb, cmd->sc_cdb_actual_len);
21561963Sap25164 break;
21571963Sap25164 }
21581963Sap25164
21590Sstevel@tonic-gate cmd->sc_cdb[0] = (uchar_t)opcode;
21600Sstevel@tonic-gate scsa1394_cmd_fill_cdb_lba(cmd, lba);
21610Sstevel@tonic-gate switch (opcode) {
21620Sstevel@tonic-gate case SCMD_READ_CD:
21630Sstevel@tonic-gate scsa1394_cmd_fill_read_cd_cdb_len(cmd, len);
21640Sstevel@tonic-gate break;
21650Sstevel@tonic-gate case SCMD_WRITE_G5:
21660Sstevel@tonic-gate case SCMD_READ_G5:
21670Sstevel@tonic-gate scsa1394_cmd_fill_12byte_cdb_len(cmd, len);
21680Sstevel@tonic-gate break;
21690Sstevel@tonic-gate default:
21700Sstevel@tonic-gate scsa1394_cmd_fill_cdb_len(cmd, len);
21710Sstevel@tonic-gate break;
21720Sstevel@tonic-gate }
21730Sstevel@tonic-gate }
21740Sstevel@tonic-gate
21750Sstevel@tonic-gate /*ARGSUSED*/
21760Sstevel@tonic-gate static void
scsa1394_cmd_fill_cdb_other(scsa1394_lun_t * lp,scsa1394_cmd_t * cmd)21770Sstevel@tonic-gate scsa1394_cmd_fill_cdb_other(scsa1394_lun_t *lp, scsa1394_cmd_t *cmd)
21780Sstevel@tonic-gate {
21790Sstevel@tonic-gate struct scsi_pkt *pkt = CMD2PKT(cmd);
21800Sstevel@tonic-gate
2181276Sartem cmd->sc_xfer_bytes = cmd->sc_win_len;
2182276Sartem cmd->sc_xfer_blks = cmd->sc_xfer_bytes / lp->l_lba_size;
2183276Sartem cmd->sc_total_blks = cmd->sc_xfer_blks;
2184276Sartem cmd->sc_lba = 0;
21850Sstevel@tonic-gate
2186276Sartem bcopy(pkt->pkt_cdbp, cmd->sc_cdb, cmd->sc_cdb_len);
21870Sstevel@tonic-gate }
21880Sstevel@tonic-gate
21890Sstevel@tonic-gate /*
21900Sstevel@tonic-gate * fill up parts of CDB
21910Sstevel@tonic-gate */
21920Sstevel@tonic-gate static void
scsa1394_cmd_fill_cdb_len(scsa1394_cmd_t * cmd,int len)21930Sstevel@tonic-gate scsa1394_cmd_fill_cdb_len(scsa1394_cmd_t *cmd, int len)
21940Sstevel@tonic-gate {
21950Sstevel@tonic-gate cmd->sc_cdb[7] = len >> 8;
21960Sstevel@tonic-gate cmd->sc_cdb[8] = (uchar_t)len;
21970Sstevel@tonic-gate }
21980Sstevel@tonic-gate
21990Sstevel@tonic-gate static void
scsa1394_cmd_fill_cdb_lba(scsa1394_cmd_t * cmd,int lba)22000Sstevel@tonic-gate scsa1394_cmd_fill_cdb_lba(scsa1394_cmd_t *cmd, int lba)
22010Sstevel@tonic-gate {
22020Sstevel@tonic-gate cmd->sc_cdb[2] = lba >> 24;
22030Sstevel@tonic-gate cmd->sc_cdb[3] = lba >> 16;
22040Sstevel@tonic-gate cmd->sc_cdb[4] = lba >> 8;
22050Sstevel@tonic-gate cmd->sc_cdb[5] = (uchar_t)lba;
22060Sstevel@tonic-gate cmd->sc_lba = lba;
22070Sstevel@tonic-gate }
22080Sstevel@tonic-gate
22090Sstevel@tonic-gate static void
scsa1394_cmd_fill_12byte_cdb_len(scsa1394_cmd_t * cmd,int len)22100Sstevel@tonic-gate scsa1394_cmd_fill_12byte_cdb_len(scsa1394_cmd_t *cmd, int len)
22110Sstevel@tonic-gate {
22120Sstevel@tonic-gate cmd->sc_cdb[6] = len >> 24;
22130Sstevel@tonic-gate cmd->sc_cdb[7] = len >> 16;
22140Sstevel@tonic-gate cmd->sc_cdb[8] = len >> 8;
22150Sstevel@tonic-gate cmd->sc_cdb[9] = (uchar_t)len;
22160Sstevel@tonic-gate }
22170Sstevel@tonic-gate
22180Sstevel@tonic-gate static void
scsa1394_cmd_fill_read_cd_cdb_len(scsa1394_cmd_t * cmd,int len)22190Sstevel@tonic-gate scsa1394_cmd_fill_read_cd_cdb_len(scsa1394_cmd_t *cmd, int len)
22200Sstevel@tonic-gate {
22210Sstevel@tonic-gate cmd->sc_cdb[6] = len >> 16;
22220Sstevel@tonic-gate cmd->sc_cdb[7] = len >> 8;
22230Sstevel@tonic-gate cmd->sc_cdb[8] = (uchar_t)len;
22240Sstevel@tonic-gate }
22250Sstevel@tonic-gate
22260Sstevel@tonic-gate /*
22270Sstevel@tonic-gate * For SCMD_READ_CD, figure out the block size based on expected sector type.
22280Sstevel@tonic-gate * See MMC SCSI Specs section 6.1.15
22290Sstevel@tonic-gate */
22300Sstevel@tonic-gate static int
scsa1394_cmd_read_cd_blk_size(uchar_t expected_sector_type)22310Sstevel@tonic-gate scsa1394_cmd_read_cd_blk_size(uchar_t expected_sector_type)
22320Sstevel@tonic-gate {
22330Sstevel@tonic-gate int blk_size;
22340Sstevel@tonic-gate
22350Sstevel@tonic-gate switch (expected_sector_type) {
22360Sstevel@tonic-gate case READ_CD_EST_CDDA:
22370Sstevel@tonic-gate blk_size = CDROM_BLK_2352;
22380Sstevel@tonic-gate break;
22390Sstevel@tonic-gate case READ_CD_EST_MODE2:
22400Sstevel@tonic-gate blk_size = CDROM_BLK_2336;
22410Sstevel@tonic-gate break;
22420Sstevel@tonic-gate case READ_CD_EST_MODE2FORM2:
22430Sstevel@tonic-gate blk_size = CDROM_BLK_2324;
22440Sstevel@tonic-gate break;
22450Sstevel@tonic-gate case READ_CD_EST_MODE2FORM1:
22460Sstevel@tonic-gate case READ_CD_EST_ALLTYPE:
22470Sstevel@tonic-gate case READ_CD_EST_MODE1:
22480Sstevel@tonic-gate default:
22490Sstevel@tonic-gate blk_size = CDROM_BLK_2048;
22500Sstevel@tonic-gate }
22510Sstevel@tonic-gate
22520Sstevel@tonic-gate return (blk_size);
22530Sstevel@tonic-gate }
22540Sstevel@tonic-gate
22550Sstevel@tonic-gate /*ARGSUSED*/
22560Sstevel@tonic-gate static int
scsa1394_cmd_fake_mode_sense(scsa1394_state_t * sp,scsa1394_cmd_t * cmd)22570Sstevel@tonic-gate scsa1394_cmd_fake_mode_sense(scsa1394_state_t *sp, scsa1394_cmd_t *cmd)
22580Sstevel@tonic-gate {
22590Sstevel@tonic-gate struct scsi_pkt *pkt = CMD2PKT(cmd);
22600Sstevel@tonic-gate struct scsi_arq_status *arqp = (struct scsi_arq_status *)pkt->pkt_scbp;
22610Sstevel@tonic-gate struct scsi_extended_sense *esp = &arqp->sts_sensedata;
22620Sstevel@tonic-gate
22630Sstevel@tonic-gate *(pkt->pkt_scbp) = STATUS_CHECK;
22640Sstevel@tonic-gate *(uint8_t *)&arqp->sts_rqpkt_status = STATUS_GOOD;
22650Sstevel@tonic-gate arqp->sts_rqpkt_reason = CMD_CMPLT;
22660Sstevel@tonic-gate arqp->sts_rqpkt_resid = 0;
22670Sstevel@tonic-gate arqp->sts_rqpkt_state |= STATE_XFERRED_DATA;
22680Sstevel@tonic-gate arqp->sts_rqpkt_statistics = 0;
22690Sstevel@tonic-gate
22700Sstevel@tonic-gate bzero(esp, sizeof (struct scsi_extended_sense));
22710Sstevel@tonic-gate
22720Sstevel@tonic-gate esp->es_class = CLASS_EXTENDED_SENSE;
22730Sstevel@tonic-gate
22740Sstevel@tonic-gate esp->es_key = KEY_ILLEGAL_REQUEST;
22750Sstevel@tonic-gate
22760Sstevel@tonic-gate pkt->pkt_reason = CMD_CMPLT;
22770Sstevel@tonic-gate pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET | STATE_SENT_CMD |
22780Sstevel@tonic-gate STATE_XFERRED_DATA | STATE_GOT_STATUS);
22790Sstevel@tonic-gate
22800Sstevel@tonic-gate if (pkt->pkt_comp) {
22810Sstevel@tonic-gate (*pkt->pkt_comp)(pkt);
22820Sstevel@tonic-gate }
22830Sstevel@tonic-gate return (DDI_SUCCESS);
22840Sstevel@tonic-gate }
22850Sstevel@tonic-gate
22860Sstevel@tonic-gate /*ARGSUSED*/
22870Sstevel@tonic-gate static int
scsa1394_cmd_fake_inquiry(scsa1394_state_t * sp,scsa1394_cmd_t * cmd)22880Sstevel@tonic-gate scsa1394_cmd_fake_inquiry(scsa1394_state_t *sp, scsa1394_cmd_t *cmd)
22890Sstevel@tonic-gate {
22900Sstevel@tonic-gate scsa1394_lun_t *lp = cmd->sc_lun;
22910Sstevel@tonic-gate struct scsi_pkt *pkt = CMD2PKT(cmd);
22920Sstevel@tonic-gate struct scsi_inquiry *inq;
22930Sstevel@tonic-gate
22940Sstevel@tonic-gate /* copy fabricated inquiry data */
22950Sstevel@tonic-gate inq = (struct scsi_inquiry *)cmd->sc_bp->b_un.b_addr;
22960Sstevel@tonic-gate bcopy(&lp->l_fake_inq, inq, sizeof (struct scsi_inquiry));
22970Sstevel@tonic-gate
22980Sstevel@tonic-gate pkt->pkt_resid -= sizeof (struct scsi_inquiry);
22990Sstevel@tonic-gate pkt->pkt_reason = CMD_CMPLT;
23000Sstevel@tonic-gate pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET | STATE_SENT_CMD |
23010Sstevel@tonic-gate STATE_XFERRED_DATA | STATE_GOT_STATUS);
23020Sstevel@tonic-gate
23030Sstevel@tonic-gate if (pkt->pkt_comp) {
23040Sstevel@tonic-gate (*pkt->pkt_comp)(pkt);
23050Sstevel@tonic-gate }
23060Sstevel@tonic-gate return (DDI_SUCCESS);
23070Sstevel@tonic-gate }
23080Sstevel@tonic-gate
23090Sstevel@tonic-gate /*
23100Sstevel@tonic-gate * If command allows fake completion (without actually being transported),
23110Sstevel@tonic-gate * call completion callback and return DDI_SUCCESS.
23120Sstevel@tonic-gate * Otherwise return DDI_FAILURE.
23130Sstevel@tonic-gate */
23140Sstevel@tonic-gate static int
scsa1394_cmd_fake_comp(scsa1394_state_t * sp,scsa1394_cmd_t * cmd)23150Sstevel@tonic-gate scsa1394_cmd_fake_comp(scsa1394_state_t *sp, scsa1394_cmd_t *cmd)
23160Sstevel@tonic-gate {
23170Sstevel@tonic-gate struct scsi_pkt *pkt = CMD2PKT(cmd);
23180Sstevel@tonic-gate scsa1394_lun_t *lp = cmd->sc_lun;
23190Sstevel@tonic-gate int ret = DDI_SUCCESS;
23200Sstevel@tonic-gate
2321276Sartem /*
2322276Sartem * agreement with sd in case of device hot removal
2323276Sartem * is to fake completion with CMD_DEV_GONE
2324276Sartem */
2325276Sartem mutex_enter(&sp->s_mutex);
2326276Sartem if (sp->s_dev_state != SCSA1394_DEV_ONLINE) {
2327276Sartem mutex_exit(&sp->s_mutex);
2328276Sartem pkt->pkt_reason = CMD_DEV_GONE;
2329276Sartem if (pkt->pkt_comp) {
2330276Sartem (*pkt->pkt_comp)(pkt);
2331276Sartem }
2332276Sartem return (DDI_SUCCESS);
2333276Sartem }
2334276Sartem mutex_exit(&sp->s_mutex);
2335276Sartem
23360Sstevel@tonic-gate mutex_enter(&lp->l_mutex);
23370Sstevel@tonic-gate
23380Sstevel@tonic-gate switch (pkt->pkt_cdbp[0]) {
23390Sstevel@tonic-gate /*
23400Sstevel@tonic-gate * RBC support for PRIN/PROUT is optional
23410Sstevel@tonic-gate */
23420Sstevel@tonic-gate case SCMD_PRIN:
23430Sstevel@tonic-gate case SCMD_PROUT:
23440Sstevel@tonic-gate if (!scsa1394_wrka_fake_prin) {
23450Sstevel@tonic-gate ret = DDI_FAILURE;
23460Sstevel@tonic-gate }
23470Sstevel@tonic-gate break;
23480Sstevel@tonic-gate /*
23490Sstevel@tonic-gate * Some fixed disks don't like doorlock cmd. And they don't need it.
23500Sstevel@tonic-gate */
23510Sstevel@tonic-gate case SCMD_DOORLOCK:
23520Sstevel@tonic-gate if (lp->l_rmb_orig != 0) {
23530Sstevel@tonic-gate ret = DDI_FAILURE;
23540Sstevel@tonic-gate }
23550Sstevel@tonic-gate break;
23560Sstevel@tonic-gate case SCMD_TEST_UNIT_READY:
23570Sstevel@tonic-gate if (!lp->l_nosup_tur) {
23580Sstevel@tonic-gate ret = DDI_FAILURE;
23590Sstevel@tonic-gate }
23600Sstevel@tonic-gate break;
23610Sstevel@tonic-gate case SCMD_START_STOP:
23620Sstevel@tonic-gate if (!lp->l_nosup_start_stop) {
23630Sstevel@tonic-gate ret = DDI_FAILURE;
23640Sstevel@tonic-gate }
23650Sstevel@tonic-gate break;
23660Sstevel@tonic-gate case SCMD_INQUIRY:
23670Sstevel@tonic-gate if (!lp->l_nosup_inquiry) {
23680Sstevel@tonic-gate ret = DDI_FAILURE;
23690Sstevel@tonic-gate } else {
23700Sstevel@tonic-gate mutex_exit(&lp->l_mutex);
23710Sstevel@tonic-gate return (scsa1394_cmd_fake_inquiry(sp, cmd));
23720Sstevel@tonic-gate }
23730Sstevel@tonic-gate break;
23740Sstevel@tonic-gate case SCMD_MODE_SENSE:
23750Sstevel@tonic-gate if (!lp->l_mode_sense_fake) {
23760Sstevel@tonic-gate ret = DDI_FAILURE;
23770Sstevel@tonic-gate } else {
23780Sstevel@tonic-gate mutex_exit(&lp->l_mutex);
23790Sstevel@tonic-gate return (scsa1394_cmd_fake_mode_sense(sp, cmd));
23800Sstevel@tonic-gate }
23810Sstevel@tonic-gate default:
23820Sstevel@tonic-gate ret = DDI_FAILURE;
23830Sstevel@tonic-gate }
23840Sstevel@tonic-gate
23850Sstevel@tonic-gate mutex_exit(&lp->l_mutex);
23860Sstevel@tonic-gate
23870Sstevel@tonic-gate if (ret != DDI_SUCCESS) {
23880Sstevel@tonic-gate return (ret);
23890Sstevel@tonic-gate }
23900Sstevel@tonic-gate
23910Sstevel@tonic-gate ASSERT(*(pkt->pkt_scbp) == STATUS_GOOD);
23920Sstevel@tonic-gate ASSERT(pkt->pkt_reason == CMD_CMPLT);
23930Sstevel@tonic-gate pkt->pkt_state |= (STATE_GOT_BUS | STATE_GOT_TARGET | STATE_SENT_CMD |
23940Sstevel@tonic-gate STATE_XFERRED_DATA | STATE_GOT_STATUS);
23950Sstevel@tonic-gate
23960Sstevel@tonic-gate if (pkt->pkt_comp) {
23970Sstevel@tonic-gate (*pkt->pkt_comp)(pkt);
23980Sstevel@tonic-gate }
23990Sstevel@tonic-gate return (DDI_SUCCESS);
24000Sstevel@tonic-gate }
24010Sstevel@tonic-gate
24020Sstevel@tonic-gate /*
24030Sstevel@tonic-gate * Returns DDI_SUCCESS if next xfer setup successfully, DDI_FAILURE otherwise.
24040Sstevel@tonic-gate */
24050Sstevel@tonic-gate static int
scsa1394_cmd_setup_next_xfer(scsa1394_lun_t * lp,scsa1394_cmd_t * cmd)24060Sstevel@tonic-gate scsa1394_cmd_setup_next_xfer(scsa1394_lun_t *lp, scsa1394_cmd_t *cmd)
24070Sstevel@tonic-gate {
24080Sstevel@tonic-gate struct scsi_pkt *pkt = CMD2PKT(cmd);
24090Sstevel@tonic-gate
24100Sstevel@tonic-gate ASSERT(cmd->sc_flags & SCSA1394_CMD_SYMBIOS_BREAKUP);
24110Sstevel@tonic-gate
24120Sstevel@tonic-gate cmd->sc_resid_blks -= cmd->sc_xfer_blks;
24130Sstevel@tonic-gate if (cmd->sc_resid_blks <= 0) {
24140Sstevel@tonic-gate pkt->pkt_resid = 0;
24150Sstevel@tonic-gate return (DDI_FAILURE);
24160Sstevel@tonic-gate }
24170Sstevel@tonic-gate
24180Sstevel@tonic-gate scsa1394_cmd_adjust_cdb(lp, cmd);
24190Sstevel@tonic-gate
24200Sstevel@tonic-gate scsa1394_sbp2_seg2pt(lp, cmd);
24210Sstevel@tonic-gate
24220Sstevel@tonic-gate scsa1394_sbp2_cmd2orb(lp, cmd);
24230Sstevel@tonic-gate
24240Sstevel@tonic-gate if (scsa1394_sbp2_start(lp, cmd) != TRAN_ACCEPT) {
24250Sstevel@tonic-gate pkt->pkt_resid = cmd->sc_resid_blks * cmd->sc_blk_size;
24260Sstevel@tonic-gate return (DDI_FAILURE);
24270Sstevel@tonic-gate }
24280Sstevel@tonic-gate
24290Sstevel@tonic-gate return (DDI_SUCCESS);
24300Sstevel@tonic-gate }
24310Sstevel@tonic-gate
24320Sstevel@tonic-gate /*
24330Sstevel@tonic-gate * new lba = current lba + previous xfer len
24340Sstevel@tonic-gate */
24350Sstevel@tonic-gate /*ARGSUSED*/
24360Sstevel@tonic-gate static void
scsa1394_cmd_adjust_cdb(scsa1394_lun_t * lp,scsa1394_cmd_t * cmd)24370Sstevel@tonic-gate scsa1394_cmd_adjust_cdb(scsa1394_lun_t *lp, scsa1394_cmd_t *cmd)
24380Sstevel@tonic-gate {
24390Sstevel@tonic-gate int len;
24400Sstevel@tonic-gate
24410Sstevel@tonic-gate ASSERT(cmd->sc_flags & SCSA1394_CMD_SYMBIOS_BREAKUP);
24420Sstevel@tonic-gate
24430Sstevel@tonic-gate cmd->sc_lba += cmd->sc_xfer_blks;
24440Sstevel@tonic-gate len = cmd->sc_resid_blks;
24450Sstevel@tonic-gate
24460Sstevel@tonic-gate /* limit xfer length for Symbios workaround */
24470Sstevel@tonic-gate if (len * cmd->sc_blk_size > scsa1394_symbios_size_max) {
24480Sstevel@tonic-gate len = scsa1394_symbios_size_max / cmd->sc_blk_size;
24490Sstevel@tonic-gate }
24500Sstevel@tonic-gate
24510Sstevel@tonic-gate switch (cmd->sc_cdb[0]) {
24520Sstevel@tonic-gate case SCMD_READ_CD:
24530Sstevel@tonic-gate scsa1394_cmd_fill_read_cd_cdb_len(cmd, len);
24540Sstevel@tonic-gate break;
24550Sstevel@tonic-gate case SCMD_WRITE_G5:
24560Sstevel@tonic-gate case SCMD_READ_G5:
24570Sstevel@tonic-gate scsa1394_cmd_fill_12byte_cdb_len(cmd, len);
24580Sstevel@tonic-gate break;
24590Sstevel@tonic-gate case SCMD_WRITE_G1:
24600Sstevel@tonic-gate case SCMD_WRITE_LONG:
24610Sstevel@tonic-gate default:
24620Sstevel@tonic-gate scsa1394_cmd_fill_cdb_len(cmd, len);
24630Sstevel@tonic-gate }
24640Sstevel@tonic-gate
24650Sstevel@tonic-gate scsa1394_cmd_fill_cdb_lba(cmd, cmd->sc_lba);
24660Sstevel@tonic-gate
24670Sstevel@tonic-gate cmd->sc_xfer_blks = len;
24680Sstevel@tonic-gate cmd->sc_xfer_bytes = len * cmd->sc_blk_size;
24690Sstevel@tonic-gate }
24700Sstevel@tonic-gate
24710Sstevel@tonic-gate void
scsa1394_cmd_status_proc(scsa1394_lun_t * lp,scsa1394_cmd_t * cmd)24720Sstevel@tonic-gate scsa1394_cmd_status_proc(scsa1394_lun_t *lp, scsa1394_cmd_t *cmd)
24730Sstevel@tonic-gate {
24740Sstevel@tonic-gate struct scsi_pkt *pkt = CMD2PKT(cmd);
24750Sstevel@tonic-gate
24760Sstevel@tonic-gate /* next iteration of partial xfer? */
24770Sstevel@tonic-gate if ((pkt->pkt_reason == CMD_CMPLT) &&
24780Sstevel@tonic-gate (cmd->sc_flags & SCSA1394_CMD_SYMBIOS_BREAKUP)) {
24790Sstevel@tonic-gate if (scsa1394_cmd_setup_next_xfer(lp, cmd) == DDI_SUCCESS) {
24800Sstevel@tonic-gate return;
24810Sstevel@tonic-gate }
24820Sstevel@tonic-gate }
24830Sstevel@tonic-gate cmd->sc_flags &= ~SCSA1394_CMD_SYMBIOS_BREAKUP;
24840Sstevel@tonic-gate
24850Sstevel@tonic-gate /* apply workarounds */
24860Sstevel@tonic-gate if (pkt->pkt_reason == CMD_CMPLT) {
24870Sstevel@tonic-gate scsa1394_cmd_status_wrka(lp, cmd);
24880Sstevel@tonic-gate }
24890Sstevel@tonic-gate
24900Sstevel@tonic-gate mutex_enter(&lp->l_mutex);
24910Sstevel@tonic-gate
24920Sstevel@tonic-gate /* mode sense workaround */
24930Sstevel@tonic-gate if (pkt->pkt_cdbp[0] == SCMD_MODE_SENSE) {
24940Sstevel@tonic-gate if (pkt->pkt_reason == CMD_CMPLT) {
24950Sstevel@tonic-gate lp->l_mode_sense_fail_cnt = 0;
24960Sstevel@tonic-gate } else if (++lp->l_mode_sense_fail_cnt >=
24970Sstevel@tonic-gate scsa1394_mode_sense_fail_max) {
24980Sstevel@tonic-gate lp->l_mode_sense_fake = B_TRUE;
24990Sstevel@tonic-gate }
25000Sstevel@tonic-gate } else {
25010Sstevel@tonic-gate lp->l_mode_sense_fail_cnt = 0;
25020Sstevel@tonic-gate }
25030Sstevel@tonic-gate
25040Sstevel@tonic-gate mutex_exit(&lp->l_mutex);
25050Sstevel@tonic-gate
25060Sstevel@tonic-gate if (pkt->pkt_comp) {
25070Sstevel@tonic-gate (*pkt->pkt_comp)(pkt);
25080Sstevel@tonic-gate }
25090Sstevel@tonic-gate }
25100Sstevel@tonic-gate
25110Sstevel@tonic-gate static void
scsa1394_cmd_status_wrka(scsa1394_lun_t * lp,scsa1394_cmd_t * cmd)25120Sstevel@tonic-gate scsa1394_cmd_status_wrka(scsa1394_lun_t *lp, scsa1394_cmd_t *cmd)
25130Sstevel@tonic-gate {
25140Sstevel@tonic-gate struct scsi_pkt *pkt = CMD2PKT(cmd);
25150Sstevel@tonic-gate
25160Sstevel@tonic-gate mutex_enter(&lp->l_mutex);
25170Sstevel@tonic-gate
25180Sstevel@tonic-gate switch (pkt->pkt_cdbp[0]) {
25190Sstevel@tonic-gate case SCMD_INQUIRY: {
25200Sstevel@tonic-gate struct scsi_inquiry *inq;
25210Sstevel@tonic-gate
25220Sstevel@tonic-gate inq = (struct scsi_inquiry *)cmd->sc_bp->b_un.b_addr;
25230Sstevel@tonic-gate
25240Sstevel@tonic-gate /* change dtype RBC to DIRECT, sd doesn't support RBC */
25250Sstevel@tonic-gate lp->l_dtype_orig = inq->inq_dtype;
25260Sstevel@tonic-gate if ((inq->inq_dtype == SCSA1394_DTYPE_RBC) &&
25270Sstevel@tonic-gate scsa1394_wrka_rbc2direct) {
25280Sstevel@tonic-gate inq->inq_dtype = DTYPE_DIRECT;
25290Sstevel@tonic-gate }
25300Sstevel@tonic-gate
25310Sstevel@tonic-gate /* force RMB to 1 */
25320Sstevel@tonic-gate lp->l_rmb_orig = inq->inq_rmb;
25331415Scg149915 if (scsa1394_wrka_fake_rmb) {
25340Sstevel@tonic-gate inq->inq_rmb = 1;
25350Sstevel@tonic-gate }
25360Sstevel@tonic-gate break;
25370Sstevel@tonic-gate }
25380Sstevel@tonic-gate case SCMD_READ_CAPACITY: {
25390Sstevel@tonic-gate uint32_t *capacity_buf;
25400Sstevel@tonic-gate
25410Sstevel@tonic-gate capacity_buf = (uint32_t *)cmd->sc_bp->b_un.b_addr;
25420Sstevel@tonic-gate
25430Sstevel@tonic-gate if (lp->l_dtype_orig != DTYPE_RODIRECT) {
25440Sstevel@tonic-gate lp->l_lba_size = min(BE_32(capacity_buf[1]), DEV_BSIZE);
25450Sstevel@tonic-gate if (lp->l_lba_size == 0) {
25460Sstevel@tonic-gate cmn_err(CE_WARN, "zero LBA size reported, "
25470Sstevel@tonic-gate "possibly broken device");
25480Sstevel@tonic-gate lp->l_lba_size = DEV_BSIZE;
25490Sstevel@tonic-gate }
25500Sstevel@tonic-gate } else {
25510Sstevel@tonic-gate lp->l_lba_size = 2048;
25520Sstevel@tonic-gate }
25530Sstevel@tonic-gate }
25540Sstevel@tonic-gate default:
25550Sstevel@tonic-gate break;
25560Sstevel@tonic-gate }
25570Sstevel@tonic-gate
25580Sstevel@tonic-gate mutex_exit(&lp->l_mutex);
25590Sstevel@tonic-gate }
25600Sstevel@tonic-gate
25610Sstevel@tonic-gate /*
25620Sstevel@tonic-gate * --- thread management
25630Sstevel@tonic-gate *
25640Sstevel@tonic-gate * dispatch a thread
25650Sstevel@tonic-gate */
25660Sstevel@tonic-gate int
scsa1394_thr_dispatch(scsa1394_thread_t * thr)25670Sstevel@tonic-gate scsa1394_thr_dispatch(scsa1394_thread_t *thr)
25680Sstevel@tonic-gate {
25690Sstevel@tonic-gate scsa1394_lun_t *lp = thr->thr_lun;
25700Sstevel@tonic-gate scsa1394_state_t *sp = lp->l_sp;
25710Sstevel@tonic-gate int ret;
25720Sstevel@tonic-gate
25730Sstevel@tonic-gate ASSERT(mutex_owned(&lp->l_mutex));
25740Sstevel@tonic-gate ASSERT(thr->thr_state == SCSA1394_THR_INIT);
25750Sstevel@tonic-gate
25760Sstevel@tonic-gate thr->thr_state = SCSA1394_THR_RUN;
25770Sstevel@tonic-gate
25780Sstevel@tonic-gate ret = ddi_taskq_dispatch(sp->s_taskq, thr->thr_func, thr->thr_arg,
25790Sstevel@tonic-gate KM_SLEEP);
25800Sstevel@tonic-gate return (ret);
25810Sstevel@tonic-gate }
25820Sstevel@tonic-gate
25830Sstevel@tonic-gate /*
25840Sstevel@tonic-gate * cancel thread
25850Sstevel@tonic-gate */
25860Sstevel@tonic-gate void
scsa1394_thr_cancel(scsa1394_thread_t * thr)25870Sstevel@tonic-gate scsa1394_thr_cancel(scsa1394_thread_t *thr)
25880Sstevel@tonic-gate {
25890Sstevel@tonic-gate scsa1394_lun_t *lp = thr->thr_lun;
25900Sstevel@tonic-gate
25910Sstevel@tonic-gate ASSERT(mutex_owned(&lp->l_mutex));
25920Sstevel@tonic-gate
25930Sstevel@tonic-gate thr->thr_req |= SCSA1394_THREQ_EXIT;
25940Sstevel@tonic-gate cv_signal(&thr->thr_cv);
25950Sstevel@tonic-gate
25960Sstevel@tonic-gate /* wait until the thread actually exits */
25970Sstevel@tonic-gate do {
25980Sstevel@tonic-gate if (cv_wait_sig(&thr->thr_cv, &lp->l_mutex) == 0) {
25990Sstevel@tonic-gate break;
26000Sstevel@tonic-gate }
26010Sstevel@tonic-gate } while (thr->thr_state != SCSA1394_THR_EXIT);
26020Sstevel@tonic-gate }
26030Sstevel@tonic-gate
26040Sstevel@tonic-gate /*
26050Sstevel@tonic-gate * wake thread
26060Sstevel@tonic-gate */
26070Sstevel@tonic-gate void
scsa1394_thr_wake(scsa1394_thread_t * thr,int req)26080Sstevel@tonic-gate scsa1394_thr_wake(scsa1394_thread_t *thr, int req)
26090Sstevel@tonic-gate {
26100Sstevel@tonic-gate scsa1394_lun_t *lp = thr->thr_lun;
26110Sstevel@tonic-gate
26120Sstevel@tonic-gate ASSERT(mutex_owned(&lp->l_mutex));
26130Sstevel@tonic-gate
26140Sstevel@tonic-gate thr->thr_req |= req;
26150Sstevel@tonic-gate cv_signal(&thr->thr_cv);
26160Sstevel@tonic-gate }
26170Sstevel@tonic-gate
26180Sstevel@tonic-gate void
scsa1394_thr_clear_req(scsa1394_thread_t * thr,int mask)26190Sstevel@tonic-gate scsa1394_thr_clear_req(scsa1394_thread_t *thr, int mask)
26200Sstevel@tonic-gate {
26210Sstevel@tonic-gate scsa1394_lun_t *lp = thr->thr_lun;
26220Sstevel@tonic-gate
26230Sstevel@tonic-gate mutex_enter(&lp->l_mutex);
26240Sstevel@tonic-gate thr->thr_req &= ~mask;
26250Sstevel@tonic-gate mutex_exit(&lp->l_mutex);
26260Sstevel@tonic-gate }
26270Sstevel@tonic-gate
26280Sstevel@tonic-gate /*
26290Sstevel@tonic-gate *
26300Sstevel@tonic-gate * --- other routines
26310Sstevel@tonic-gate *
26320Sstevel@tonic-gate */
26330Sstevel@tonic-gate static boolean_t
scsa1394_is_my_child(dev_info_t * dip)26340Sstevel@tonic-gate scsa1394_is_my_child(dev_info_t *dip)
26350Sstevel@tonic-gate {
26360Sstevel@tonic-gate return ((dip != NULL) && (ddi_prop_exists(DDI_DEV_T_ANY, dip,
26370Sstevel@tonic-gate DDI_PROP_DONTPASS, "scsa1394") == 1));
26380Sstevel@tonic-gate }
26390Sstevel@tonic-gate
26400Sstevel@tonic-gate boolean_t
scsa1394_dev_is_online(scsa1394_state_t * sp)26410Sstevel@tonic-gate scsa1394_dev_is_online(scsa1394_state_t *sp)
26420Sstevel@tonic-gate {
26430Sstevel@tonic-gate boolean_t ret;
26440Sstevel@tonic-gate
26450Sstevel@tonic-gate mutex_enter(&sp->s_mutex);
26460Sstevel@tonic-gate ret = (sp->s_dev_state == SCSA1394_DEV_ONLINE);
26470Sstevel@tonic-gate mutex_exit(&sp->s_mutex);
26480Sstevel@tonic-gate
26490Sstevel@tonic-gate return (ret);
26500Sstevel@tonic-gate }
26510Sstevel@tonic-gate
26520Sstevel@tonic-gate static void *
scsa1394_kmem_realloc(void * old_buf,int old_size,int new_size,size_t elsize,int kf)26530Sstevel@tonic-gate scsa1394_kmem_realloc(void *old_buf, int old_size, int new_size, size_t elsize,
26540Sstevel@tonic-gate int kf)
26550Sstevel@tonic-gate {
26560Sstevel@tonic-gate void *new_buf;
26570Sstevel@tonic-gate
26580Sstevel@tonic-gate new_buf = kmem_zalloc(new_size * elsize, kf);
26590Sstevel@tonic-gate
26600Sstevel@tonic-gate if (old_size > 0) {
26610Sstevel@tonic-gate if (new_buf != NULL) {
26620Sstevel@tonic-gate bcopy(old_buf, new_buf, old_size * elsize);
26630Sstevel@tonic-gate }
26640Sstevel@tonic-gate kmem_free(old_buf, old_size * elsize);
26650Sstevel@tonic-gate }
26660Sstevel@tonic-gate
26670Sstevel@tonic-gate return (new_buf);
26680Sstevel@tonic-gate }
2669