Home | History | Annotate | Download | only in io
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     27 
     28 /*
     29  * pseudo scsi disk driver
     30  */
     31 
     32 #include <sys/scsi/scsi.h>
     33 #include <sys/ddi.h>
     34 #include <sys/sunddi.h>
     35 #include <sys/kmem.h>
     36 #include <sys/taskq.h>
     37 #include <sys/disp.h>
     38 #include <sys/types.h>
     39 #include <sys/buf.h>
     40 
     41 #include <sys/emul64.h>
     42 #include <sys/emul64cmd.h>
     43 #include <sys/emul64var.h>
     44 
     45 /*
     46  * Mode sense/select page control
     47  */
     48 #define	MODE_SENSE_PC_CURRENT		0
     49 #define	MODE_SENSE_PC_CHANGEABLE	1
     50 #define	MODE_SENSE_PC_DEFAULT		2
     51 #define	MODE_SENSE_PC_SAVED		3
     52 
     53 /*
     54  * Byte conversion macros
     55  */
     56 #if	defined(_BIG_ENDIAN)
     57 #define	ushort_to_scsi_ushort(n)	(n)
     58 #define	uint32_to_scsi_uint32(n)	(n)
     59 #define	uint64_to_scsi_uint64(n)	(n)
     60 #elif	defined(_LITTLE_ENDIAN)
     61 
     62 #define	ushort_to_scsi_ushort(n)			\
     63 		((((n) & 0x00ff) << 8) |		\
     64 		(((n)  & 0xff00) >> 8))
     65 
     66 #define	uint32_to_scsi_uint32(n)			\
     67 		((((n) & 0x000000ff) << 24) |		\
     68 		(((n)  & 0x0000ff00) << 8) |		\
     69 		(((n)  & 0x00ff0000) >> 8) |		\
     70 		(((n)  & 0xff000000) >> 24))
     71 #define	uint64_to_scsi_uint64(n)				\
     72 		((((n) & 0x00000000000000ff) << 56) |           \
     73 		(((n)  & 0x000000000000ff00) << 40) |           \
     74 		(((n)  & 0x0000000000ff0000) << 24) |           \
     75 		(((n)  & 0x00000000ff000000) << 8) |            \
     76 		(((n)  & 0x000000ff00000000) >> 8) |            \
     77 		(((n)  & 0x0000ff0000000000) >> 24) |           \
     78 		(((n)  & 0x00ff000000000000) >> 40) |           \
     79 		(((n)  & 0xff00000000000000) >> 56))
     80 #else
     81 error no _BIG_ENDIAN or _LITTLE_ENDIAN
     82 #endif
     83 #define	uint_to_byte0(n)		((n) & 0xff)
     84 #define	uint_to_byte1(n)		(((n)>>8) & 0xff)
     85 #define	uint_to_byte2(n)		(((n)>>16) & 0xff)
     86 #define	uint_to_byte3(n)		(((n)>>24) & 0xff)
     87 
     88 /*
     89  * struct prop_map
     90  *
     91  * This structure maps a property name to the place to store its value.
     92  */
     93 struct prop_map {
     94 	char 		*pm_name;	/* Name of the property. */
     95 	int		*pm_value;	/* Place to store the value. */
     96 };
     97 
     98 static int emul64_debug_blklist = 0;
     99 
    100 /*
    101  * Some interesting statistics.  These are protected by the
    102  * emul64_stats_mutex.  It would be nice to have an ioctl to print them out,
    103  * but we don't have the development time for that now.  You can at least
    104  * look at them with adb.
    105  */
    106 
    107 int		emul64_collect_stats = 1; /* Collect stats if non-zero */
    108 kmutex_t	emul64_stats_mutex;	/* Protect these variables */
    109 long		emul64_nowrite_count = 0; /* # active nowrite ranges */
    110 static uint64_t	emul64_skipped_io = 0;	/* Skipped I/O operations, because of */
    111 					/* EMUL64_WRITE_OFF. */
    112 static uint64_t	emul64_skipped_blk = 0;	/* Skipped blocks because of */
    113 					/* EMUL64_WRITE_OFF. */
    114 static uint64_t	emul64_io_ops = 0;	/* Total number of I/O operations */
    115 					/* including skipped and actual. */
    116 static uint64_t	emul64_io_blocks = 0;	/* Total number of blocks involved */
    117 					/* in I/O operations. */
    118 static uint64_t	emul64_nonzero = 0;	/* Number of non-zero data blocks */
    119 					/* currently held in memory */
    120 static uint64_t	emul64_max_list_length = 0; /* Maximum size of a linked */
    121 					    /* list of non-zero blocks. */
    122 uint64_t emul64_taskq_max = 0;		/* emul64_scsi_start uses the taskq */
    123 					/* mechanism to dispatch work. */
    124 					/* If the number of entries in the */
    125 					/* exceeds the maximum for the queue */
    126 					/* the queue a 1 second delay is */
    127 					/* encountered in taskq_ent_alloc. */
    128 					/* This counter counts the number */
    129 					/* times that this happens. */
    130 
    131 /*
    132  * Since emul64 does no physical I/O, operations that would normally be I/O
    133  * intensive become CPU bound.  An example of this is RAID 5
    134  * initialization.  When the kernel becomes CPU bound, it looks as if the
    135  * machine is hung.
    136  *
    137  * To avoid this problem, we provide a function, emul64_yield_check, that does a
    138  * delay from time to time to yield up the CPU.  The following variables
    139  * are tunables for this algorithm.
    140  *
    141  *	emul64_num_delay_called	Number of times we called delay.  This is
    142  *				not really a tunable.  Rather it is a
    143  *				counter that provides useful information
    144  *				for adjusting the tunables.
    145  *	emul64_yield_length	Number of microseconds to yield the CPU.
    146  *	emul64_yield_period	Number of I/O operations between yields.
    147  *	emul64_yield_enable	emul64 will yield the CPU, only if this
    148  *				variable contains a non-zero value.  This
    149  *				allows the yield functionality to be turned
    150  *				off for experimentation purposes.
    151  *
    152  * The value of 1000 for emul64_yield_period has been determined by
    153  * experience with running the tests.
    154  */
    155 static uint64_t		emul64_num_delay_called = 0;
    156 static int		emul64_yield_length = 1000;
    157 static int		emul64_yield_period = 1000;
    158 static int		emul64_yield_enable = 1;
    159 static kmutex_t		emul64_yield_mutex;
    160 static kcondvar_t 	emul64_yield_cv;
    161 
    162 /*
    163  * This array establishes a set of tunable variables that can be set by
    164  * defining properties in the emul64.conf file.
    165  */
    166 struct prop_map emul64_properties[] = {
    167 	"emul64_collect_stats",		&emul64_collect_stats,
    168 	"emul64_yield_length",		&emul64_yield_length,
    169 	"emul64_yield_period",		&emul64_yield_period,
    170 	"emul64_yield_enable",		&emul64_yield_enable,
    171 	"emul64_max_task",		&emul64_max_task,
    172 	"emul64_task_nthreads",		&emul64_task_nthreads
    173 };
    174 
    175 static unsigned char *emul64_zeros = NULL; /* Block of 0s for comparison */
    176 
    177 extern void emul64_check_cond(struct scsi_pkt *pkt, uchar_t key,
    178 				uchar_t asc, uchar_t ascq);
    179 /* ncyl=250000 acyl=2 nhead=24 nsect=357 */
    180 uint_t dkg_rpm = 3600;
    181 
    182 static int bsd_mode_sense_dad_mode_geometry(struct scsi_pkt *);
    183 static int bsd_mode_sense_dad_mode_err_recov(struct scsi_pkt *);
    184 static int bsd_mode_sense_modepage_disco_reco(struct scsi_pkt *);
    185 static int bsd_mode_sense_dad_mode_format(struct scsi_pkt *);
    186 static int bsd_mode_sense_dad_mode_cache(struct scsi_pkt *);
    187 static int bsd_readblks(struct emul64 *, ushort_t, ushort_t, diskaddr_t,
    188 				int, unsigned char *);
    189 static int bsd_writeblks(struct emul64 *, ushort_t, ushort_t, diskaddr_t,
    190 				int, unsigned char *);
    191 emul64_tgt_t *find_tgt(struct emul64 *, ushort_t, ushort_t);
    192 static blklist_t *bsd_findblk(emul64_tgt_t *, diskaddr_t, avl_index_t *);
    193 static void bsd_allocblk(emul64_tgt_t *, diskaddr_t, caddr_t, avl_index_t);
    194 static void bsd_freeblk(emul64_tgt_t *, blklist_t *);
    195 static void emul64_yield_check();
    196 static emul64_rng_overlap_t bsd_tgt_overlap(emul64_tgt_t *, diskaddr_t, int);
    197 
    198 char *emul64_name = "emul64";
    199 
    200 
    201 /*
    202  * Initialize globals in this file.
    203  */
    204 void
    205 emul64_bsd_init()
    206 {
    207 	emul64_zeros = (unsigned char *) kmem_zalloc(DEV_BSIZE, KM_SLEEP);
    208 	mutex_init(&emul64_stats_mutex, NULL, MUTEX_DRIVER, NULL);
    209 	mutex_init(&emul64_yield_mutex, NULL, MUTEX_DRIVER, NULL);
    210 	cv_init(&emul64_yield_cv, NULL, CV_DRIVER, NULL);
    211 }
    212 
    213 /*
    214  * Clean up globals in this file.
    215  */
    216 void
    217 emul64_bsd_fini()
    218 {
    219 	cv_destroy(&emul64_yield_cv);
    220 	mutex_destroy(&emul64_yield_mutex);
    221 	mutex_destroy(&emul64_stats_mutex);
    222 	if (emul64_zeros != NULL) {
    223 		kmem_free(emul64_zeros, DEV_BSIZE);
    224 		emul64_zeros = NULL;
    225 	}
    226 }
    227 
    228 /*
    229  * Attempt to get the values of the properties that are specified in the
    230  * emul64_properties array.  If the property exists, copy its value to the
    231  * specified location.  All the properties have been assigned default
    232  * values in this driver, so if we cannot get the property that is not a
    233  * problem.
    234  */
    235 void
    236 emul64_bsd_get_props(dev_info_t *dip)
    237 {
    238 	uint_t		count;
    239 	uint_t		i;
    240 	struct prop_map	*pmp;
    241 	int		*properties;
    242 
    243 	for (pmp = emul64_properties, i = 0;
    244 		i < sizeof (emul64_properties) / sizeof (struct prop_map);
    245 		i++, pmp++) {
    246 		if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
    247 				DDI_PROP_DONTPASS,
    248 				pmp->pm_name, &properties,
    249 				&count) == DDI_PROP_SUCCESS) {
    250 			if (count >= 1) {
    251 				*pmp->pm_value = *properties;
    252 			}
    253 			ddi_prop_free((void *) properties);
    254 		}
    255 	}
    256 }
    257 
    258 int
    259 emul64_bsd_blkcompare(const void *a1, const void *b1)
    260 {
    261 	blklist_t	*a = (blklist_t *)a1;
    262 	blklist_t	*b = (blklist_t *)b1;
    263 
    264 	if (a->bl_blkno < b->bl_blkno)
    265 		return (-1);
    266 	if (a->bl_blkno == b->bl_blkno)
    267 		return (0);
    268 	return (1);
    269 }
    270 
    271 /* ARGSUSED 0 */
    272 int
    273 bsd_scsi_start_stop_unit(struct scsi_pkt *pkt)
    274 {
    275 	return (0);
    276 }
    277 
    278 /* ARGSUSED 0 */
    279 int
    280 bsd_scsi_test_unit_ready(struct scsi_pkt *pkt)
    281 {
    282 	return (0);
    283 }
    284 
    285 /* ARGSUSED 0 */
    286 int
    287 bsd_scsi_request_sense(struct scsi_pkt *pkt)
    288 {
    289 	return (0);
    290 }
    291 
    292 int
    293 bsd_scsi_inq_page0(struct scsi_pkt *pkt, uchar_t pqdtype)
    294 {
    295 	struct emul64_cmd	*sp = PKT2CMD(pkt);
    296 
    297 	if (sp->cmd_count < 6) {
    298 		cmn_err(CE_CONT, "%s: bsd_scsi_inq_page0: size %d required\n",
    299 		    emul64_name, 6);
    300 		return (EIO);
    301 	}
    302 
    303 	sp->cmd_addr[0] = pqdtype;	/* periph qual., dtype */
    304 	sp->cmd_addr[1] = 0;		/* page code */
    305 	sp->cmd_addr[2] = 0;		/* reserved */
    306 	sp->cmd_addr[3] = 6 - 3;	/* length */
    307 	sp->cmd_addr[4] = 0;		/* 1st page */
    308 	sp->cmd_addr[5] = 0x83;		/* 2nd page */
    309 
    310 	pkt->pkt_resid = sp->cmd_count - 6;
    311 	return (0);
    312 }
    313 
    314 int
    315 bsd_scsi_inq_page83(struct scsi_pkt *pkt, uchar_t pqdtype)
    316 {
    317 	struct emul64		*emul64 = PKT2EMUL64(pkt);
    318 	struct emul64_cmd	*sp = PKT2CMD(pkt);
    319 	int			instance = ddi_get_instance(emul64->emul64_dip);
    320 
    321 	if (sp->cmd_count < 22) {
    322 		cmn_err(CE_CONT, "%s: bsd_scsi_inq_page83: size %d required\n",
    323 		    emul64_name, 22);
    324 		return (EIO);
    325 	}
    326 
    327 	sp->cmd_addr[0] = pqdtype;	/* periph qual., dtype */
    328 	sp->cmd_addr[1] = 0x83;		/* page code */
    329 	sp->cmd_addr[2] = 0;		/* reserved */
    330 	sp->cmd_addr[3] = (22 - 8) + 4;	/* length */
    331 
    332 	sp->cmd_addr[4] = 1;		/* code set - binary */
    333 	sp->cmd_addr[5] = 3;		/* association and device ID type 3 */
    334 	sp->cmd_addr[6] = 0;		/* reserved */
    335 	sp->cmd_addr[7] = 22 - 8;	/* ID length */
    336 
    337 	sp->cmd_addr[8] = 0xde;		/* @8: identifier, byte 0 */
    338 	sp->cmd_addr[9] = 0xca;
    339 	sp->cmd_addr[10] = 0xde;
    340 	sp->cmd_addr[11] = 0x80;
    341 
    342 	sp->cmd_addr[12] = 0xba;
    343 	sp->cmd_addr[13] = 0xbe;
    344 	sp->cmd_addr[14] = 0xab;
    345 	sp->cmd_addr[15] = 0xba;
    346 					/* @22: */
    347 
    348 	/*
    349 	 * Instances seem to be assigned sequentially, so it unlikely that we
    350 	 * will have more than 65535 of them.
    351 	 */
    352 	sp->cmd_addr[16] = uint_to_byte1(instance);
    353 	sp->cmd_addr[17] = uint_to_byte0(instance);
    354 	sp->cmd_addr[18] = uint_to_byte1(TGT(sp));
    355 	sp->cmd_addr[19] = uint_to_byte0(TGT(sp));
    356 	sp->cmd_addr[20] = uint_to_byte1(LUN(sp));
    357 	sp->cmd_addr[21] = uint_to_byte0(LUN(sp));
    358 
    359 	pkt->pkt_resid = sp->cmd_count - 22;
    360 	return (0);
    361 }
    362 
    363 int
    364 bsd_scsi_inquiry(struct scsi_pkt *pkt)
    365 {
    366 	struct emul64_cmd	*sp = PKT2CMD(pkt);
    367 	union scsi_cdb		*cdb = (union scsi_cdb *)pkt->pkt_cdbp;
    368 	emul64_tgt_t		*tgt;
    369 	uchar_t			pqdtype;
    370 	struct scsi_inquiry	inq;
    371 
    372 	EMUL64_MUTEX_ENTER(sp->cmd_emul64);
    373 	tgt = find_tgt(sp->cmd_emul64,
    374 	    pkt->pkt_address.a_target, pkt->pkt_address.a_lun);
    375 	EMUL64_MUTEX_EXIT(sp->cmd_emul64);
    376 
    377 	if (sp->cmd_count < sizeof (inq)) {
    378 		cmn_err(CE_CONT, "%s: bsd_scsi_inquiry: size %d required\n",
    379 		    emul64_name, (int)sizeof (inq));
    380 		return (EIO);
    381 	}
    382 
    383 	if (cdb->cdb_opaque[1] & 0xfc) {
    384 		cmn_err(CE_WARN, "%s: bsd_scsi_inquiry: 0x%x",
    385 		    emul64_name, cdb->cdb_opaque[1]);
    386 		emul64_check_cond(pkt, 0x5, 0x24, 0x0);	/* inv. fld in cdb */
    387 		return (0);
    388 	}
    389 
    390 	pqdtype = tgt->emul64_tgt_dtype;
    391 	if (cdb->cdb_opaque[1] & 0x1) {
    392 		switch (cdb->cdb_opaque[2]) {
    393 			case 0x00:
    394 				return (bsd_scsi_inq_page0(pkt, pqdtype));
    395 			case 0x83:
    396 				return (bsd_scsi_inq_page83(pkt, pqdtype));
    397 			default:
    398 				cmn_err(CE_WARN, "%s: bsd_scsi_inquiry: "
    399 				    "unsupported 0x%x",
    400 				    emul64_name, cdb->cdb_opaque[2]);
    401 				return (0);
    402 		}
    403 	}
    404 
    405 	/* set up the inquiry data we return */
    406 	(void) bzero((void *)&inq, sizeof (inq));
    407 
    408 	inq.inq_dtype = pqdtype;
    409 	inq.inq_ansi = 2;
    410 	inq.inq_rdf = 2;
    411 	inq.inq_len = sizeof (inq) - 4;
    412 	inq.inq_wbus16 = 1;
    413 	inq.inq_cmdque = 1;
    414 
    415 	(void) bcopy(tgt->emul64_tgt_inq, inq.inq_vid,
    416 	    sizeof (tgt->emul64_tgt_inq));
    417 	(void) bcopy("1", inq.inq_revision, 2);
    418 	(void) bcopy((void *)&inq, sp->cmd_addr, sizeof (inq));
    419 
    420 	pkt->pkt_resid = sp->cmd_count - sizeof (inq);
    421 	return (0);
    422 }
    423 
    424 /* ARGSUSED 0 */
    425 int
    426 bsd_scsi_format(struct scsi_pkt *pkt)
    427 {
    428 	return (0);
    429 }
    430 
    431 int
    432 bsd_scsi_io(struct scsi_pkt *pkt)
    433 {
    434 	struct emul64_cmd	*sp = PKT2CMD(pkt);
    435 	union scsi_cdb		*cdb = (union scsi_cdb *)pkt->pkt_cdbp;
    436 	diskaddr_t		lblkno;
    437 	int			nblks;
    438 
    439 	switch (cdb->scc_cmd) {
    440 	case SCMD_READ:
    441 			lblkno = (uint32_t)GETG0ADDR(cdb);
    442 			nblks = GETG0COUNT(cdb);
    443 			pkt->pkt_resid = bsd_readblks(sp->cmd_emul64,
    444 					pkt->pkt_address.a_target,
    445 					pkt->pkt_address.a_lun,
    446 					lblkno, nblks, sp->cmd_addr);
    447 			if (emul64debug) {
    448 				cmn_err(CE_CONT, "%s: bsd_scsi_io: "
    449 				    "read g0 blk=%lld (0x%llx) nblks=%d\n",
    450 				    emul64_name, lblkno, lblkno, nblks);
    451 			}
    452 		break;
    453 	case SCMD_WRITE:
    454 			lblkno = (uint32_t)GETG0ADDR(cdb);
    455 			nblks = GETG0COUNT(cdb);
    456 			pkt->pkt_resid = bsd_writeblks(sp->cmd_emul64,
    457 					pkt->pkt_address.a_target,
    458 					pkt->pkt_address.a_lun,
    459 					lblkno, nblks, sp->cmd_addr);
    460 			if (emul64debug) {
    461 				cmn_err(CE_CONT, "%s: bsd_scsi_io: "
    462 				    "write g0 blk=%lld (0x%llx) nblks=%d\n",
    463 				    emul64_name, lblkno, lblkno, nblks);
    464 			}
    465 		break;
    466 	case SCMD_READ_G1:
    467 			lblkno = (uint32_t)GETG1ADDR(cdb);
    468 			nblks = GETG1COUNT(cdb);
    469 			pkt->pkt_resid = bsd_readblks(sp->cmd_emul64,
    470 					pkt->pkt_address.a_target,
    471 					pkt->pkt_address.a_lun,
    472 					lblkno, nblks, sp->cmd_addr);
    473 			if (emul64debug) {
    474 				cmn_err(CE_CONT, "%s: bsd_scsi_io: "
    475 				    "read g1 blk=%lld (0x%llx) nblks=%d\n",
    476 				    emul64_name, lblkno, lblkno, nblks);
    477 			}
    478 		break;
    479 	case SCMD_WRITE_G1:
    480 			lblkno = (uint32_t)GETG1ADDR(cdb);
    481 			nblks = GETG1COUNT(cdb);
    482 			pkt->pkt_resid = bsd_writeblks(sp->cmd_emul64,
    483 					pkt->pkt_address.a_target,
    484 					pkt->pkt_address.a_lun,
    485 					lblkno, nblks, sp->cmd_addr);
    486 			if (emul64debug) {
    487 				cmn_err(CE_CONT, "%s: bsd_scsi_io: "
    488 				    "write g1 blk=%lld (0x%llx) nblks=%d\n",
    489 				    emul64_name, lblkno, lblkno, nblks);
    490 			}
    491 		break;
    492 	case SCMD_READ_G4:
    493 			lblkno = GETG4ADDR(cdb);
    494 			lblkno <<= 32;
    495 			lblkno |= (uint32_t)GETG4ADDRTL(cdb);
    496 			nblks = GETG4COUNT(cdb);
    497 			pkt->pkt_resid = bsd_readblks(sp->cmd_emul64,
    498 					pkt->pkt_address.a_target,
    499 					pkt->pkt_address.a_lun,
    500 					lblkno, nblks, sp->cmd_addr);
    501 			if (emul64debug) {
    502 				cmn_err(CE_CONT, "%s: bsd_scsi_io: "
    503 				    "read g4 blk=%lld (0x%llx) nblks=%d\n",
    504 				    emul64_name, lblkno, lblkno, nblks);
    505 			}
    506 		break;
    507 	case SCMD_WRITE_G4:
    508 			lblkno = GETG4ADDR(cdb);
    509 			lblkno <<= 32;
    510 			lblkno |= (uint32_t)GETG4ADDRTL(cdb);
    511 			nblks = GETG4COUNT(cdb);
    512 			pkt->pkt_resid = bsd_writeblks(sp->cmd_emul64,
    513 					pkt->pkt_address.a_target,
    514 					pkt->pkt_address.a_lun,
    515 					lblkno, nblks, sp->cmd_addr);
    516 			if (emul64debug) {
    517 				cmn_err(CE_CONT, "%s: bsd_scsi_io: "
    518 				    "write g4 blk=%lld (0x%llx) nblks=%d\n",
    519 				    emul64_name, lblkno, lblkno, nblks);
    520 			}
    521 		break;
    522 	default:
    523 		cmn_err(CE_WARN, "%s: bsd_scsi_io: unhandled I/O: 0x%x",
    524 		    emul64_name, cdb->scc_cmd);
    525 		break;
    526 	}
    527 
    528 	if (pkt->pkt_resid != 0)
    529 		cmn_err(CE_WARN, "%s: bsd_scsi_io: "
    530 		    "pkt_resid: 0x%lx, lblkno %lld, nblks %d",
    531 		    emul64_name, pkt->pkt_resid, lblkno, nblks);
    532 
    533 	return (0);
    534 }
    535 
    536 int
    537 bsd_scsi_log_sense(struct scsi_pkt *pkt)
    538 {
    539 	union scsi_cdb		*cdb = (union scsi_cdb *)pkt->pkt_cdbp;
    540 	struct emul64_cmd	*sp = PKT2CMD(pkt);
    541 	int			page_code;
    542 
    543 	if (sp->cmd_count < 9) {
    544 		cmn_err(CE_CONT, "%s: bsd_scsi_log_sense size %d required\n",
    545 		    emul64_name, 9);
    546 		return (EIO);
    547 	}
    548 
    549 	page_code = cdb->cdb_opaque[2] & 0x3f;
    550 	if (page_code) {
    551 		cmn_err(CE_CONT, "%s: bsd_scsi_log_sense: "
    552 		    "page 0x%x not supported\n", emul64_name, page_code);
    553 		emul64_check_cond(pkt, 0x5, 0x24, 0x0); /* inv. fld in cdb */
    554 		return (0);
    555 	}
    556 
    557 	sp->cmd_addr[0] = 0;		/* page code */
    558 	sp->cmd_addr[1] = 0;		/* reserved */
    559 	sp->cmd_addr[2] = 0;		/* MSB of page length */
    560 	sp->cmd_addr[3] = 8 - 3;	/* LSB of page length */
    561 
    562 	sp->cmd_addr[4] = 0;		/* MSB of parameter code */
    563 	sp->cmd_addr[5] = 0;		/* LSB of parameter code */
    564 	sp->cmd_addr[6] = 0;		/* parameter control byte */
    565 	sp->cmd_addr[7] = 4 - 3;	/* parameter length */
    566 	sp->cmd_addr[8] = 0x0;		/* parameter value */
    567 
    568 	pkt->pkt_resid = sp->cmd_count - 9;
    569 	return (0);
    570 }
    571 
    572 int
    573 bsd_scsi_mode_sense(struct scsi_pkt *pkt)
    574 {
    575 	union scsi_cdb	*cdb = (union scsi_cdb *)pkt->pkt_cdbp;
    576 	int		page_control;
    577 	int		page_code;
    578 	int		rval = 0;
    579 
    580 	switch (cdb->scc_cmd) {
    581 	case SCMD_MODE_SENSE:
    582 			page_code = cdb->cdb_opaque[2] & 0x3f;
    583 			page_control = (cdb->cdb_opaque[2] >> 6) & 0x03;
    584 			if (emul64debug) {
    585 				cmn_err(CE_CONT, "%s: bsd_scsi_mode_sense: "
    586 				    "page=0x%x control=0x%x nbytes=%d\n",
    587 				    emul64_name, page_code, page_control,
    588 				    GETG0COUNT(cdb));
    589 			}
    590 		break;
    591 	case SCMD_MODE_SENSE_G1:
    592 			page_code = cdb->cdb_opaque[2] & 0x3f;
    593 			page_control = (cdb->cdb_opaque[2] >> 6) & 0x03;
    594 			if (emul64debug) {
    595 				cmn_err(CE_CONT, "%s: bsd_scsi_mode_sense: "
    596 				    "page=0x%x control=0x%x nbytes=%d\n",
    597 				    emul64_name, page_code, page_control,
    598 				    GETG1COUNT(cdb));
    599 			}
    600 		break;
    601 	default:
    602 		cmn_err(CE_CONT, "%s: bsd_scsi_mode_sense: "
    603 		    "cmd 0x%x not supported\n", emul64_name, cdb->scc_cmd);
    604 		return (EIO);
    605 	}
    606 
    607 	switch (page_code) {
    608 	case DAD_MODE_GEOMETRY:
    609 		rval = bsd_mode_sense_dad_mode_geometry(pkt);
    610 		break;
    611 	case DAD_MODE_ERR_RECOV:
    612 		rval = bsd_mode_sense_dad_mode_err_recov(pkt);
    613 		break;
    614 	case MODEPAGE_DISCO_RECO:
    615 		rval = bsd_mode_sense_modepage_disco_reco(pkt);
    616 		break;
    617 	case DAD_MODE_FORMAT:
    618 		rval = bsd_mode_sense_dad_mode_format(pkt);
    619 		break;
    620 	case DAD_MODE_CACHE:
    621 		rval = bsd_mode_sense_dad_mode_cache(pkt);
    622 		break;
    623 	default:
    624 		cmn_err(CE_CONT, "%s: bsd_scsi_mode_sense: "
    625 		    "page 0x%x not supported\n", emul64_name, page_code);
    626 		rval = EIO;
    627 		break;
    628 	}
    629 
    630 	return (rval);
    631 }
    632 
    633 
    634 static int
    635 bsd_mode_sense_dad_mode_geometry(struct scsi_pkt *pkt)
    636 {
    637 	struct emul64_cmd	*sp = PKT2CMD(pkt);
    638 	union scsi_cdb		*cdb = (union scsi_cdb *)pkt->pkt_cdbp;
    639 	uchar_t			*addr = (uchar_t *)sp->cmd_addr;
    640 	emul64_tgt_t		*tgt;
    641 	int			page_control;
    642 	struct mode_header	header;
    643 	struct mode_geometry	page4;
    644 	int			ncyl;
    645 	int			rval = 0;
    646 
    647 	page_control = (cdb->cdb_opaque[2] >> 6) & 0x03;
    648 
    649 	if (emul64debug) {
    650 		cmn_err(CE_CONT, "%s: bsd_mode_sense_dad_mode_geometry: "
    651 		    "pc=%d n=%d\n", emul64_name, page_control, sp->cmd_count);
    652 	}
    653 
    654 	if (sp->cmd_count < (sizeof (header) + sizeof (page4))) {
    655 		cmn_err(CE_CONT, "%s: bsd_mode_sense_dad_mode_geometry: "
    656 		    "size %d required\n",
    657 		    emul64_name, (int)(sizeof (header) + sizeof (page4)));
    658 		return (EIO);
    659 	}
    660 
    661 	(void) bzero(&header, sizeof (header));
    662 	(void) bzero(&page4, sizeof (page4));
    663 
    664 	header.length = sizeof (header) + sizeof (page4) - 1;
    665 	header.bdesc_length = 0;
    666 
    667 	page4.mode_page.code = DAD_MODE_GEOMETRY;
    668 	page4.mode_page.ps = 1;
    669 	page4.mode_page.length = sizeof (page4) - sizeof (struct mode_page);
    670 
    671 	switch (page_control) {
    672 	case MODE_SENSE_PC_CURRENT:
    673 	case MODE_SENSE_PC_DEFAULT:
    674 	case MODE_SENSE_PC_SAVED:
    675 		EMUL64_MUTEX_ENTER(sp->cmd_emul64);
    676 		tgt = find_tgt(sp->cmd_emul64,
    677 		    pkt->pkt_address.a_target, pkt->pkt_address.a_lun);
    678 		EMUL64_MUTEX_EXIT(sp->cmd_emul64);
    679 		ncyl = tgt->emul64_tgt_ncyls;
    680 		page4.cyl_ub = uint_to_byte2(ncyl);
    681 		page4.cyl_mb = uint_to_byte1(ncyl);
    682 		page4.cyl_lb = uint_to_byte0(ncyl);
    683 		page4.heads = uint_to_byte0(tgt->emul64_tgt_nheads);
    684 		page4.rpm = ushort_to_scsi_ushort(dkg_rpm);
    685 		break;
    686 	case MODE_SENSE_PC_CHANGEABLE:
    687 		page4.cyl_ub = 0xff;
    688 		page4.cyl_mb = 0xff;
    689 		page4.cyl_lb = 0xff;
    690 		page4.heads = 0xff;
    691 		page4.rpm = 0xffff;
    692 		break;
    693 	}
    694 
    695 	(void) bcopy(&header, addr, sizeof (header));
    696 	(void) bcopy(&page4, addr + sizeof (header), sizeof (page4));
    697 
    698 	pkt->pkt_resid = sp->cmd_count - sizeof (page4) - sizeof (header);
    699 	rval = 0;
    700 
    701 	return (rval);
    702 }
    703 
    704 static int
    705 bsd_mode_sense_dad_mode_err_recov(struct scsi_pkt *pkt)
    706 {
    707 	struct emul64_cmd	*sp = PKT2CMD(pkt);
    708 	union scsi_cdb		*cdb = (union scsi_cdb *)pkt->pkt_cdbp;
    709 	uchar_t			*addr = (uchar_t *)sp->cmd_addr;
    710 	int			page_control;
    711 	struct mode_header	header;
    712 	struct mode_err_recov	page1;
    713 	int			rval = 0;
    714 
    715 	page_control = (cdb->cdb_opaque[2] >> 6) & 0x03;
    716 
    717 	if (emul64debug) {
    718 		cmn_err(CE_CONT, "%s: bsd_mode_sense_dad_mode_err_recov: "
    719 		    "pc=%d n=%d\n", emul64_name, page_control, sp->cmd_count);
    720 	}
    721 
    722 	if (sp->cmd_count < (sizeof (header) + sizeof (page1))) {
    723 		cmn_err(CE_CONT, "%s: bsd_mode_sense_dad_mode_err_recov: "
    724 		    "size %d required\n",
    725 		    emul64_name, (int)(sizeof (header) + sizeof (page1)));
    726 		return (EIO);
    727 	}
    728 
    729 	(void) bzero(&header, sizeof (header));
    730 	(void) bzero(&page1, sizeof (page1));
    731 
    732 	header.length = sizeof (header) + sizeof (page1) - 1;
    733 	header.bdesc_length = 0;
    734 
    735 	page1.mode_page.code = DAD_MODE_ERR_RECOV;
    736 	page1.mode_page.ps = 1;
    737 	page1.mode_page.length = sizeof (page1) - sizeof (struct mode_page);
    738 
    739 	switch (page_control) {
    740 	case MODE_SENSE_PC_CURRENT:
    741 	case MODE_SENSE_PC_DEFAULT:
    742 	case MODE_SENSE_PC_SAVED:
    743 		break;
    744 	case MODE_SENSE_PC_CHANGEABLE:
    745 		break;
    746 	}
    747 
    748 	(void) bcopy(&header, addr, sizeof (header));
    749 	(void) bcopy(&page1, addr + sizeof (header), sizeof (page1));
    750 
    751 	pkt->pkt_resid = sp->cmd_count - sizeof (page1) - sizeof (header);
    752 	rval = 0;
    753 
    754 	return (rval);
    755 }
    756 
    757 static int
    758 bsd_mode_sense_modepage_disco_reco(struct scsi_pkt *pkt)
    759 {
    760 	struct emul64_cmd	*sp = PKT2CMD(pkt);
    761 	union scsi_cdb		*cdb = (union scsi_cdb *)pkt->pkt_cdbp;
    762 	int			rval = 0;
    763 	uchar_t			*addr = (uchar_t *)sp->cmd_addr;
    764 	int			page_control;
    765 	struct mode_header	header;
    766 	struct mode_disco_reco	page2;
    767 
    768 	page_control = (cdb->cdb_opaque[2] >> 6) & 0x03;
    769 
    770 	if (emul64debug) {
    771 		cmn_err(CE_CONT, "%s: bsd_mode_sense_modepage_disco_reco: "
    772 		    "pc=%d n=%d\n", emul64_name, page_control, sp->cmd_count);
    773 	}
    774 
    775 	if (sp->cmd_count < (sizeof (header) + sizeof (page2))) {
    776 		cmn_err(CE_CONT, "%s: bsd_mode_sense_modepage_disco_reco: "
    777 		    "size %d required\n",
    778 		    emul64_name, (int)(sizeof (header) + sizeof (page2)));
    779 		return (EIO);
    780 	}
    781 
    782 	(void) bzero(&header, sizeof (header));
    783 	(void) bzero(&page2, sizeof (page2));
    784 
    785 	header.length = sizeof (header) + sizeof (page2) - 1;
    786 	header.bdesc_length = 0;
    787 
    788 	page2.mode_page.code = MODEPAGE_DISCO_RECO;
    789 	page2.mode_page.ps = 1;
    790 	page2.mode_page.length = sizeof (page2) - sizeof (struct mode_page);
    791 
    792 	switch (page_control) {
    793 	case MODE_SENSE_PC_CURRENT:
    794 	case MODE_SENSE_PC_DEFAULT:
    795 	case MODE_SENSE_PC_SAVED:
    796 		break;
    797 	case MODE_SENSE_PC_CHANGEABLE:
    798 		break;
    799 	}
    800 
    801 	(void) bcopy(&header, addr, sizeof (header));
    802 	(void) bcopy(&page2, addr + sizeof (header), sizeof (page2));
    803 
    804 	pkt->pkt_resid = sp->cmd_count - sizeof (page2) - sizeof (header);
    805 	rval = 0;
    806 
    807 	return (rval);
    808 }
    809 
    810 static int
    811 bsd_mode_sense_dad_mode_format(struct scsi_pkt *pkt)
    812 {
    813 	struct emul64_cmd	*sp = PKT2CMD(pkt);
    814 	union scsi_cdb		*cdb = (union scsi_cdb *)pkt->pkt_cdbp;
    815 	uchar_t			*addr = (uchar_t *)sp->cmd_addr;
    816 	emul64_tgt_t		*tgt;
    817 	int			page_control;
    818 	struct mode_header	header;
    819 	struct mode_format	page3;
    820 	int			rval = 0;
    821 
    822 	page_control = (cdb->cdb_opaque[2] >> 6) & 0x03;
    823 
    824 	if (emul64debug) {
    825 		cmn_err(CE_CONT, "%s: bsd_mode_sense_dad_mode_format: "
    826 		    "pc=%d n=%d\n", emul64_name, page_control, sp->cmd_count);
    827 	}
    828 
    829 	if (sp->cmd_count < (sizeof (header) + sizeof (page3))) {
    830 		cmn_err(CE_CONT, "%s: bsd_mode_sense_dad_mode_format: "
    831 		    "size %d required\n",
    832 		    emul64_name, (int)(sizeof (header) + sizeof (page3)));
    833 		return (EIO);
    834 	}
    835 
    836 	(void) bzero(&header, sizeof (header));
    837 	(void) bzero(&page3, sizeof (page3));
    838 
    839 	header.length = sizeof (header) + sizeof (page3) - 1;
    840 	header.bdesc_length = 0;
    841 
    842 	page3.mode_page.code = DAD_MODE_FORMAT;
    843 	page3.mode_page.ps = 1;
    844 	page3.mode_page.length = sizeof (page3) - sizeof (struct mode_page);
    845 
    846 	switch (page_control) {
    847 	case MODE_SENSE_PC_CURRENT:
    848 	case MODE_SENSE_PC_DEFAULT:
    849 	case MODE_SENSE_PC_SAVED:
    850 		page3.data_bytes_sect = ushort_to_scsi_ushort(DEV_BSIZE);
    851 		page3.interleave = ushort_to_scsi_ushort(1);
    852 		EMUL64_MUTEX_ENTER(sp->cmd_emul64);
    853 		tgt = find_tgt(sp->cmd_emul64,
    854 			pkt->pkt_address.a_target, pkt->pkt_address.a_lun);
    855 		EMUL64_MUTEX_EXIT(sp->cmd_emul64);
    856 		page3.sect_track = ushort_to_scsi_ushort(tgt->emul64_tgt_nsect);
    857 		break;
    858 	case MODE_SENSE_PC_CHANGEABLE:
    859 		break;
    860 	}
    861 
    862 	(void) bcopy(&header, addr, sizeof (header));
    863 	(void) bcopy(&page3, addr + sizeof (header), sizeof (page3));
    864 
    865 	pkt->pkt_resid = sp->cmd_count - sizeof (page3) - sizeof (header);
    866 	rval = 0;
    867 
    868 	return (rval);
    869 }
    870 
    871 static int
    872 bsd_mode_sense_dad_mode_cache(struct scsi_pkt *pkt)
    873 {
    874 	struct emul64_cmd	*sp = PKT2CMD(pkt);
    875 	union scsi_cdb		*cdb = (union scsi_cdb *)pkt->pkt_cdbp;
    876 	uchar_t			*addr = (uchar_t *)sp->cmd_addr;
    877 	int			page_control;
    878 	struct mode_header	header;
    879 	struct mode_cache	page8;
    880 	int			rval = 0;
    881 
    882 	page_control = (cdb->cdb_opaque[2] >> 6) & 0x03;
    883 
    884 	if (emul64debug) {
    885 		cmn_err(CE_CONT, "%s: bsd_mode_sense_dad_mode_cache: "
    886 		    "pc=%d n=%d\n", emul64_name, page_control, sp->cmd_count);
    887 	}
    888 
    889 	if (sp->cmd_count < (sizeof (header) + sizeof (page8))) {
    890 		cmn_err(CE_CONT, "%s: bsd_mode_sense_dad_mode_cache: "
    891 		    "size %d required\n",
    892 		    emul64_name, (int)(sizeof (header) + sizeof (page8)));
    893 		return (EIO);
    894 	}
    895 
    896 	(void) bzero(&header, sizeof (header));
    897 	(void) bzero(&page8, sizeof (page8));
    898 
    899 	header.length = sizeof (header) + sizeof (page8) - 1;
    900 	header.bdesc_length = 0;
    901 
    902 	page8.mode_page.code = DAD_MODE_CACHE;
    903 	page8.mode_page.ps = 1;
    904 	page8.mode_page.length = sizeof (page8) - sizeof (struct mode_page);
    905 
    906 	switch (page_control) {
    907 	case MODE_SENSE_PC_CURRENT:
    908 	case MODE_SENSE_PC_DEFAULT:
    909 	case MODE_SENSE_PC_SAVED:
    910 		break;
    911 	case MODE_SENSE_PC_CHANGEABLE:
    912 		break;
    913 	}
    914 
    915 	(void) bcopy(&header, addr, sizeof (header));
    916 	(void) bcopy(&page8, addr + sizeof (header), sizeof (page8));
    917 
    918 	pkt->pkt_resid = sp->cmd_count - sizeof (page8) - sizeof (header);
    919 	rval = 0;
    920 
    921 	return (rval);
    922 }
    923 
    924 /* ARGSUSED 0 */
    925 int
    926 bsd_scsi_mode_select(struct scsi_pkt *pkt)
    927 {
    928 	return (0);
    929 }
    930 
    931 int
    932 bsd_scsi_read_capacity_8(struct scsi_pkt *pkt)
    933 {
    934 	struct emul64_cmd	*sp = PKT2CMD(pkt);
    935 	emul64_tgt_t		*tgt;
    936 	struct scsi_capacity	cap;
    937 	int			rval = 0;
    938 
    939 	EMUL64_MUTEX_ENTER(sp->cmd_emul64);
    940 	tgt = find_tgt(sp->cmd_emul64,
    941 		pkt->pkt_address.a_target, pkt->pkt_address.a_lun);
    942 	EMUL64_MUTEX_EXIT(sp->cmd_emul64);
    943 	if (tgt->emul64_tgt_sectors > 0xffffffff)
    944 		cap.capacity = 0xffffffff;
    945 	else
    946 		cap.capacity =
    947 		    uint32_to_scsi_uint32(tgt->emul64_tgt_sectors);
    948 	cap.lbasize = uint32