xref: /onnv-gate/usr/src/cmd/smserverd/smediad.c (revision 1137:32f68d2364fc)
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
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
230Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate #include <stdio.h>
300Sstevel@tonic-gate #include <errno.h>
310Sstevel@tonic-gate #include <ctype.h>
320Sstevel@tonic-gate #include <syslog.h>
330Sstevel@tonic-gate #include <signal.h>
340Sstevel@tonic-gate #include <limits.h>
350Sstevel@tonic-gate #include <unistd.h>
360Sstevel@tonic-gate #include <sys/types.h>
370Sstevel@tonic-gate #include <sys/mman.h>
380Sstevel@tonic-gate #include <stdlib.h>
390Sstevel@tonic-gate #include <sys/stat.h>
400Sstevel@tonic-gate #include <sys/mkdev.h>
410Sstevel@tonic-gate #include <fcntl.h>
420Sstevel@tonic-gate #include <sys/scsi/scsi.h>
430Sstevel@tonic-gate #include <sys/scsi/generic/commands.h>
440Sstevel@tonic-gate #include <string.h>
450Sstevel@tonic-gate #include <door.h>
460Sstevel@tonic-gate #include <pwd.h>
470Sstevel@tonic-gate #include <thread.h>
480Sstevel@tonic-gate #include <synch.h>
490Sstevel@tonic-gate #include <pthread.h>
500Sstevel@tonic-gate #include <locale.h>
510Sstevel@tonic-gate #include <sys/resource.h>
520Sstevel@tonic-gate #include <netconfig.h>
530Sstevel@tonic-gate #include <sys/smedia.h>
540Sstevel@tonic-gate #include "smserver.h"
550Sstevel@tonic-gate #include <rpc/rpc.h>
560Sstevel@tonic-gate #include "smed.h"
570Sstevel@tonic-gate #include "myaudit.h"
580Sstevel@tonic-gate #include <bsm/libbsm.h>
590Sstevel@tonic-gate #include <bsm/audit_uevents.h>
600Sstevel@tonic-gate #include <utmpx.h>
610Sstevel@tonic-gate 
620Sstevel@tonic-gate 
630Sstevel@tonic-gate /*
640Sstevel@tonic-gate  * The comments below would help in understanding what is being attempted
650Sstevel@tonic-gate  * in the server.
660Sstevel@tonic-gate  *
670Sstevel@tonic-gate  * The server can be started either by inetd or by the client directly.
680Sstevel@tonic-gate  * Normally the server is started by inetd when the client invokes the
690Sstevel@tonic-gate  * appropriate libsmedia library call(smedia_get_handle).
700Sstevel@tonic-gate  * However since the inetd runs only at init level 2 and above a mechanism
710Sstevel@tonic-gate  * is provided for the server to be started if an attempt is made to use
720Sstevel@tonic-gate  * the libsmedia calls in maintenence mode(init level 1).
730Sstevel@tonic-gate  * The main() routine determines how the server was invoked and takes
740Sstevel@tonic-gate  * the necessary action.
750Sstevel@tonic-gate  * When started by inetd it registers itself as an RPC program.
760Sstevel@tonic-gate  * The server also implements a mechanism by which it removes itself
770Sstevel@tonic-gate  * after a period of inactivity. The period of inactivity is specified
780Sstevel@tonic-gate  * by SVC_CLOSEDOWN which is set at 180 secs.
790Sstevel@tonic-gate  * The logic of detecting inactivity is as follows:
800Sstevel@tonic-gate  *
810Sstevel@tonic-gate  * Two variables svcstate and svccount are used to determine if the server
820Sstevel@tonic-gate  * is IDLE.
830Sstevel@tonic-gate  * The svcstate is set to 1(_SERVED) when ever the server does any operation
840Sstevel@tonic-gate  * on behalf of the client.
850Sstevel@tonic-gate  * The svccount indicates the number of active clients who have established
860Sstevel@tonic-gate  * a connection with the server. A connection is established when the
870Sstevel@tonic-gate  * libsmedia call smedia_get_handle() succeeds.
880Sstevel@tonic-gate  * The connection is broken when the client calls smedia_free_handle() OR
890Sstevel@tonic-gate  * exits.
900Sstevel@tonic-gate  * A thread called closedown is started up when server is started.
910Sstevel@tonic-gate  * This thread runs periodically and monitors both svcstate and svccount.
920Sstevel@tonic-gate  * If svcstate is IDLE and svccount is 0 then server exits.
930Sstevel@tonic-gate  * The svcstate is set to IDLE by the closedown thread. It is set to _SERVED
940Sstevel@tonic-gate  * by server. It is possible for the state to be _SERVED and the svccount
950Sstevel@tonic-gate  * to be 0. The server could be kept busy by client calls of smedia_get_handle
960Sstevel@tonic-gate  * that do not succeed. This is the reason for using both svcstate and svccount
970Sstevel@tonic-gate  * to determine the true server state.
980Sstevel@tonic-gate  *
990Sstevel@tonic-gate  * The communication between client and server is thru door calls.
1000Sstevel@tonic-gate  * Below are the door descriptors available to communicate to the server.
1010Sstevel@tonic-gate  *
1020Sstevel@tonic-gate  * main_door_descriptor:
1030Sstevel@tonic-gate  * ---------------------
1040Sstevel@tonic-gate  * 	This is a predefined descriptor used by client to establish a
1050Sstevel@tonic-gate  * connection with the server. This descriptor is available to the client
1060Sstevel@tonic-gate  * as /var/adm/smedia_svc
107*1137Sarutz  * The client uses the main_door_descriptor to obtain a dedicated
1080Sstevel@tonic-gate  * client_door_descriptor for itself. The smedia_get_handle call communicates
1090Sstevel@tonic-gate  * to the server using the main_door_descriptor and obtains the
1100Sstevel@tonic-gate  * client_door_descriptor which is stored in the handle structure.
1110Sstevel@tonic-gate  * All other libsmedia calls use the client_door_descriptor to communicate
1120Sstevel@tonic-gate  * with the server.
1130Sstevel@tonic-gate  *
1140Sstevel@tonic-gate  * client_door_descriptor:
1150Sstevel@tonic-gate  * -----------------------
1160Sstevel@tonic-gate  *	This is the door descriptor that is used by the clients to
1170Sstevel@tonic-gate  * request server to perform the necessary tasks. This door descriptor is
1180Sstevel@tonic-gate  * available only to the client for whom it was created.
1190Sstevel@tonic-gate  *
1200Sstevel@tonic-gate  * death_door_descriptor:
1210Sstevel@tonic-gate  * ----------------------
122*1137Sarutz  * 	The sole function of this descriptor HAD been to inform the server of
123*1137Sarutz  * the untimely death of the client. This descriptor is no longer used, though
124*1137Sarutz  * it is still created, as libsmedia expects to use it.  This descriptor's
125*1137Sarutz  * service procedure had used pthread cancellation(5) to terminate the thread of
126*1137Sarutz  * the associated client_door_descriptor.  The client_door_descriptor now
127*1137Sarutz  * handles the scenarios where a door_call/client are aborted/terminated.
1280Sstevel@tonic-gate  *
129*1137Sarutz  * main_servproc()
1300Sstevel@tonic-gate  * -------------
1310Sstevel@tonic-gate  *	This is the routine associated with the main_door_descriptor.
1320Sstevel@tonic-gate  * This is the routine that handles the smedia_get_handle() call
1330Sstevel@tonic-gate  * of the client. If the door call to this routine succeeds it creates a
1340Sstevel@tonic-gate  * client_door_descriptor that is used by the client in subsequent library
1350Sstevel@tonic-gate  * calls.
1360Sstevel@tonic-gate  * This client_door_descriptor is passed to the client thru the door_return
1370Sstevel@tonic-gate  * call. This client_door_descriptor cannot be used by any other process other
1380Sstevel@tonic-gate  * than the client process that obtained it.
1390Sstevel@tonic-gate  * In addition to the client_door_descriptor a death_door_descriptor is also
1400Sstevel@tonic-gate  * created by the main server and passed on to the client. The client does not
141*1137Sarutz  * use the death_door_descriptor.
1420Sstevel@tonic-gate  *
143*1137Sarutz  * client_servproc()
1440Sstevel@tonic-gate  * ---------------
1450Sstevel@tonic-gate  *	This is the routine that handles the libsmedia calls of the
1460Sstevel@tonic-gate  * client. In the current implementation the server takes control of the
1470Sstevel@tonic-gate  * number of threads that handle the door calls. This is done by creating the
1480Sstevel@tonic-gate  * door descriptor as DOOR_PRIVATE.
1490Sstevel@tonic-gate  * The server runs only one thread per handle. This makes the implementation
1500Sstevel@tonic-gate  * simple as we do not have to use mutex to make the code MT safe.
151*1137Sarutz  * The server thread has a data structure door_data_t associated with it.
1520Sstevel@tonic-gate  *
1530Sstevel@tonic-gate  * door_data_t
1540Sstevel@tonic-gate  * -----------
155*1137Sarutz  * This is the data structure that is created by the main_servproc when it
1560Sstevel@tonic-gate  * creates the client_door_descriptor. The door mechanism has a way to associate
1570Sstevel@tonic-gate  * a cookie with the door descriptor. door_data_t is the cookie for the
158*1137Sarutz  * client_door_descriptor. This cookie is passed to the server function that
159*1137Sarutz  * handles the client_door_descriptor calls. In our case it is the
160*1137Sarutz  * client_servproc routine.
1610Sstevel@tonic-gate  * The key elements of the door_data_t are the following:
1620Sstevel@tonic-gate  *
1630Sstevel@tonic-gate  *	dd_fd		file descriptor for the device.
1640Sstevel@tonic-gate  *	dd_buf		The shared memory buffer between client-server.
1650Sstevel@tonic-gate  *	dd_thread	The thread that handles the door_calls.
1660Sstevel@tonic-gate  *
1670Sstevel@tonic-gate  * signal handling:
1680Sstevel@tonic-gate  * ----------------
1690Sstevel@tonic-gate  *		The main purpose of trapping the signals is to exit gracefully
1700Sstevel@tonic-gate  * from the server after recording the appropriate message in the syslog.
1710Sstevel@tonic-gate  * This will help the administrator to determine the cause of failure of the
1720Sstevel@tonic-gate  * server by examining the log file.
1730Sstevel@tonic-gate  *
1740Sstevel@tonic-gate  * cleanup()
1750Sstevel@tonic-gate  * ---------
1760Sstevel@tonic-gate  *	This routine frees up all the resources allocated for the client.
177*1137Sarutz  * Resources include the file descriptor, shared memory, threads.
1780Sstevel@tonic-gate  *
1790Sstevel@tonic-gate  * shared memory
1800Sstevel@tonic-gate  * -------------
1810Sstevel@tonic-gate  *	In order to reduce the overheads of moving large amounts of data
1820Sstevel@tonic-gate  * during raw read/write operations, the server uses the mmapped data of
1830Sstevel@tonic-gate  * client. The smedia_raw_read, smedia_raw_write library calls mmap the
1840Sstevel@tonic-gate  * memory and pass on the file descriptor that maps the memory to the server.
1850Sstevel@tonic-gate  * The server subsequently uses this mmapped memory during the IO.
1860Sstevel@tonic-gate  * If the mmapped memory changes in size, the server is informed and it
1870Sstevel@tonic-gate  * remaps the memory to the changed size.
1880Sstevel@tonic-gate  */
1890Sstevel@tonic-gate #ifdef DEBUG
1900Sstevel@tonic-gate #define	DEFAULT_VERBOSE		1
1910Sstevel@tonic-gate #define	DEFAULT_DEBUG		1
1920Sstevel@tonic-gate #else
1930Sstevel@tonic-gate #define	DEFAULT_VERBOSE		0
1940Sstevel@tonic-gate #define	DEFAULT_DEBUG		0
1950Sstevel@tonic-gate #endif
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate #define	N_BADSIGS		(sizeof (badsigs)/sizeof (badsigs[0]))
1980Sstevel@tonic-gate #define	MD_LEN			30
1990Sstevel@tonic-gate #define	MAXUGNAME		10
2000Sstevel@tonic-gate #define	SVC_CLOSEDOWN 		180
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate /*
2030Sstevel@tonic-gate  * We will NOT be permitting the following USCI cmd options.
2040Sstevel@tonic-gate  *
2050Sstevel@tonic-gate  * RESET of target
2060Sstevel@tonic-gate  * RESET of  Bus.
2070Sstevel@tonic-gate  * Tagged commands to device
2080Sstevel@tonic-gate  * Explicitly setting SYNC/ASYNC mode of operations.
2090Sstevel@tonic-gate  * POLLED MODE of operation.
2100Sstevel@tonic-gate  * Explicitly setting NO DISCONNECT features.
2110Sstevel@tonic-gate  * use of RESERVED flags.
2120Sstevel@tonic-gate  */
2130Sstevel@tonic-gate #define	FORBIDDEN_FLAGS		(USCSI_RESET | USCSI_RESET_ALL | USCSI_RENEGOT \
2140Sstevel@tonic-gate 				| USCSI_ASYNC  | USCSI_SYNC | USCSI_NOINTR | \
2150Sstevel@tonic-gate 				USCSI_NOTAG | USCSI_NOPARITY | USCSI_NODISCON \
2160Sstevel@tonic-gate 				| USCSI_RESERVED)
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate /* States a server can be in wrt request */
2190Sstevel@tonic-gate 
2200Sstevel@tonic-gate #define	_IDLE 0
2210Sstevel@tonic-gate #define	_SERVED 1
2220Sstevel@tonic-gate 
2230Sstevel@tonic-gate static char		*prog_name;
2240Sstevel@tonic-gate static int svcstate = _IDLE;	/* Set when a request is serviced */
2250Sstevel@tonic-gate static int svccount = 0;	/* Number of requests being serviced */
2260Sstevel@tonic-gate static int svcstart_level = 0;	/* init level when server was started */
2270Sstevel@tonic-gate static mutex_t svcstate_lock;	/* lock for svcstate, svccount */
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate extern	void smserverprog_1(struct svc_req *, SVCXPRT *);
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate /*
2320Sstevel@tonic-gate  * Log messages
2330Sstevel@tonic-gate  */
2340Sstevel@tonic-gate #define	SIGACT_FAILED	"Failed to install signal handler for %s: %s"
2350Sstevel@tonic-gate #define	BADSIG_MSG	"Thread %d Caught signal %d addr=%p trapno=%d pc=%p"
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate static int	badsigs[] = {SIGSEGV, SIGBUS, SIGFPE, SIGILL};
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate /* global variables */
2400Sstevel@tonic-gate int		verbose		= DEFAULT_VERBOSE;
2410Sstevel@tonic-gate int		debug_level	= DEFAULT_DEBUG;
2420Sstevel@tonic-gate char		*smediad_devdir = DEFAULT_SMEDIAD_DEVDIR;
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate thread_key_t	door_key;
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate server_data_t	server_data;
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate static int	server_door, server_fd;
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate static int32_t do_uscsi_cmd(int32_t file, struct uscsi_cmd *uscsi_cmd,
2510Sstevel@tonic-gate 		int32_t flag);
252*1137Sarutz static void client_servproc(void *cookie, char *argp, size_t arg_size,
2530Sstevel@tonic-gate 		door_desc_t *dp, uint_t ndesc);
2540Sstevel@tonic-gate static void cleanup(door_data_t *);
2550Sstevel@tonic-gate static void *init_server(void *);
2560Sstevel@tonic-gate static int32_t scsi_reassign_block(int32_t fd, diskaddr_t);
2570Sstevel@tonic-gate static int32_t get_mode_page(int32_t fd, uchar_t pc, uchar_t page_code,
258*1137Sarutz 	uchar_t *md_data, uchar_t data_len);
2590Sstevel@tonic-gate static int32_t get_device_type(char *v_name);
2600Sstevel@tonic-gate static int32_t get_device_type_scsi(int32_t fd, struct scsi_inquiry *inq);
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate static int32_t scsi_format(int32_t fd, uint_t flavor, uint_t mode);
2630Sstevel@tonic-gate static int32_t scsi_media_status(int32_t fd);
2640Sstevel@tonic-gate static int32_t scsi_write_protect(int32_t fd, smwp_state_t *wp);
2650Sstevel@tonic-gate static int32_t scsi_floppy_media_status(int32_t fd);
2660Sstevel@tonic-gate static int32_t scsi_floppy_write_protect(int32_t fd, smwp_state_t *wp);
2670Sstevel@tonic-gate static int32_t scsi_floppy_format(int32_t, uint_t, uint_t);
2680Sstevel@tonic-gate static int32_t get_floppy_geom(int32_t fd, uint32_t capacity,
2690Sstevel@tonic-gate 			struct dk_geom *dkgeom);
2700Sstevel@tonic-gate static int32_t get_media_capacity(int32_t fd, uint32_t *capacity,
2710Sstevel@tonic-gate 			uint32_t *blocksize);
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate static int32_t scsi_ls120_format(uint_t fd, uint_t flavor, uint32_t capacity,
2740Sstevel@tonic-gate 			uint32_t blocksize);
2750Sstevel@tonic-gate 
276*1137Sarutz static void *sm_server_thread(void *arg);
277*1137Sarutz static void sm_door_server_create(door_info_t *dip);
2780Sstevel@tonic-gate static void term_handler(int sig, siginfo_t *siginfo, void *sigctx);
2790Sstevel@tonic-gate static void hup_handler(int sig, siginfo_t *siginfo, void *sigctx);
2800Sstevel@tonic-gate static void sig_handler(int sig, siginfo_t *siginfo, void *sigctx);
2810Sstevel@tonic-gate static void badsig_handler(int sig, siginfo_t *siginfo, void *sigctx);
2820Sstevel@tonic-gate static void server_badsig_handler(int sig, siginfo_t *siginfo, void *sigctx);
2830Sstevel@tonic-gate static char *xlate_state(int32_t);
2840Sstevel@tonic-gate static uint32_t	get_sector_size(int fd);
2850Sstevel@tonic-gate static int32_t raw_read(door_data_t *door_dp, smedia_services_t *req);
2860Sstevel@tonic-gate static int32_t raw_write(door_data_t *door_dp, smedia_services_t *req);
2870Sstevel@tonic-gate static int32_t reassign_block(door_data_t *door_dp, smedia_services_t *req);
2880Sstevel@tonic-gate static int32_t set_protection_status(door_data_t *door_dp,
2890Sstevel@tonic-gate 			smedia_services_t *req);
2900Sstevel@tonic-gate static int32_t set_shfd(door_data_t *door_dp, int32_t fd,
2910Sstevel@tonic-gate 			smedia_services_t *req);
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate static void door_ret_err(smedia_reterror_t *reterror, int32_t err);
2940Sstevel@tonic-gate static void my_door_return(char *data_ptr, size_t data_size,
2950Sstevel@tonic-gate 			door_desc_t *desc_ptr, uint_t num_desc);
2960Sstevel@tonic-gate static int32_t invalid_uscsi_operation(door_data_t *, struct uscsi_cmd *);
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate #define	W_E_MASK	0x80
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate static smserver_info server_info;
3010Sstevel@tonic-gate 
3020Sstevel@tonic-gate static int32_t
3030Sstevel@tonic-gate invalid_uscsi_operation(door_data_t *door_dp, struct uscsi_cmd *ucmd)
3040Sstevel@tonic-gate {
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate 	if (door_dp->dd_dkinfo.dki_ctype != DKC_CDROM) {
3070Sstevel@tonic-gate 		debug(5,
3080Sstevel@tonic-gate 		"Invalid device type(0x%x) found for uscsi cmd.\n",
3090Sstevel@tonic-gate 			door_dp->dd_dkinfo.dki_ctype);
3100Sstevel@tonic-gate 		errno = EINVAL;
3110Sstevel@tonic-gate 		return (EINVAL);
3120Sstevel@tonic-gate 	}
3130Sstevel@tonic-gate 	if (ucmd->uscsi_flags & FORBIDDEN_FLAGS) {
3140Sstevel@tonic-gate 		debug(5,
3150Sstevel@tonic-gate 		"Invalid flags(0x%x) set in uscsi cmd. cdb[0]=0x%x\n",
3160Sstevel@tonic-gate 		ucmd->uscsi_flags,  ucmd->uscsi_cdb[0]);
3170Sstevel@tonic-gate 		errno = EINVAL;
3180Sstevel@tonic-gate 		return (EINVAL);
3190Sstevel@tonic-gate 	}
3200Sstevel@tonic-gate 	if (ucmd->uscsi_cdb[0] == SCMD_COPY ||
3210Sstevel@tonic-gate 	    ucmd->uscsi_cdb[0] == SCMD_COPY_VERIFY ||
3220Sstevel@tonic-gate 	    ucmd->uscsi_cdb[0] == SCMD_COMPARE ||
3230Sstevel@tonic-gate 	    ucmd->uscsi_cdb[0] == SCMD_WRITE_BUFFER) {
3240Sstevel@tonic-gate 		debug(5,
3250Sstevel@tonic-gate 		"Invalid command(0x%x) found in cdb.\n",
3260Sstevel@tonic-gate 		ucmd->uscsi_cdb[0]);
3270Sstevel@tonic-gate 		errno = EINVAL;
3280Sstevel@tonic-gate 		return (EINVAL);
3290Sstevel@tonic-gate 	}
3300Sstevel@tonic-gate 	return (0);
3310Sstevel@tonic-gate }
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate static uint32_t
3340Sstevel@tonic-gate get_sector_size(int fd)
3350Sstevel@tonic-gate {
3360Sstevel@tonic-gate 	uint32_t	sector_size;
3370Sstevel@tonic-gate 	struct uscsi_cmd	ucmd;
3380Sstevel@tonic-gate 	union scsi_cdb		cdb;
3390Sstevel@tonic-gate 	int32_t		ret_val;
3400Sstevel@tonic-gate 	uint32_t rc_data[2];
3410Sstevel@tonic-gate 	char rq_data[RQ_LEN];
3420Sstevel@tonic-gate 
3430Sstevel@tonic-gate 	cdb.scc_cmd = SCMD_READ_CAPACITY;
3440Sstevel@tonic-gate 	ucmd.uscsi_cdb = (caddr_t)&cdb;
3450Sstevel@tonic-gate 	ucmd.uscsi_cdblen = CDB_GROUP1;
3460Sstevel@tonic-gate 	ucmd.uscsi_bufaddr = (caddr_t)&rc_data;
3470Sstevel@tonic-gate 	ucmd.uscsi_buflen = sizeof (rc_data);
3480Sstevel@tonic-gate 	ucmd.uscsi_timeout = 120; /* If 0, HBA hangs forever */
3490Sstevel@tonic-gate 	ucmd.uscsi_rqlen = RQ_LEN;
3500Sstevel@tonic-gate 	ucmd.uscsi_rqbuf = rq_data;
3510Sstevel@tonic-gate 
3520Sstevel@tonic-gate 	ret_val = do_uscsi_cmd(fd,
3530Sstevel@tonic-gate 		&ucmd, USCSI_READ|USCSI_RQENABLE);
3540Sstevel@tonic-gate 	if (ret_val || ucmd.uscsi_status) {
3550Sstevel@tonic-gate 		debug(5, "Read capacity : %d - %d errno = %d\n",
3560Sstevel@tonic-gate 			ret_val, ucmd.uscsi_status, errno);
3570Sstevel@tonic-gate 		sector_size = 512;
3580Sstevel@tonic-gate 	} else {
3590Sstevel@tonic-gate 		sector_size = ntohl(rc_data[1]);
3600Sstevel@tonic-gate 	}
3610Sstevel@tonic-gate 	debug(5, "sector size = 0x%x(%d)\n",
3620Sstevel@tonic-gate 		sector_size, sector_size);
3630Sstevel@tonic-gate 	return (sector_size);
3640Sstevel@tonic-gate }
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate static char *
3670Sstevel@tonic-gate xlate_state(int32_t state)
3680Sstevel@tonic-gate {
3690Sstevel@tonic-gate 	switch (state) {
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate 	case SM_WRITE_PROTECT_DISABLE:
3720Sstevel@tonic-gate 		return ("PROTECTION_DISABLED");
3730Sstevel@tonic-gate 	case SM_WRITE_PROTECT_PASSWD:
3740Sstevel@tonic-gate 		return ("WRITE_PROTECT_PASSWD");
3750Sstevel@tonic-gate 	case SM_WRITE_PROTECT_NOPASSWD:
3760Sstevel@tonic-gate 		return ("WRITE_PROTECT_NOPASSWD");
3770Sstevel@tonic-gate 	case SM_READ_WRITE_PROTECT:
3780Sstevel@tonic-gate 		return ("READ_WRITE_PROTECT");
3790Sstevel@tonic-gate 	case SM_TEMP_UNLOCK_MODE:
3800Sstevel@tonic-gate 		return ("PROTECTION DISABLED");
3810Sstevel@tonic-gate 	default:
3820Sstevel@tonic-gate 		return ("UNKNOWN_STATE");
3830Sstevel@tonic-gate 	}
3840Sstevel@tonic-gate }
3850Sstevel@tonic-gate 
3860Sstevel@tonic-gate static char *
3870Sstevel@tonic-gate xlate_cnum(smedia_callnumber_t cnum)
3880Sstevel@tonic-gate {
3890Sstevel@tonic-gate 	switch (cnum) {
3900Sstevel@tonic-gate 
3910Sstevel@tonic-gate 	case SMEDIA_CNUM_OPEN_FD:
3920Sstevel@tonic-gate 		return ("SMEDIA_CNUM_OPEN_FD");
3930Sstevel@tonic-gate 	case SMEDIA_CNUM_GET_DEVICE_INFO:
3940Sstevel@tonic-gate 		return ("SMEDIA_CNUM_GET_DEVICE_INFO");
3950Sstevel@tonic-gate 	case SMEDIA_CNUM_GET_MEDIUM_PROPERTY:
3960Sstevel@tonic-gate 		return ("SMEDIA_CNUM_GET_MEDIUM_PROPERTY");
3970Sstevel@tonic-gate 	case SMEDIA_CNUM_GET_PROTECTION_STATUS:
3980Sstevel@tonic-gate 		return ("SMEDIA_CNUM_GET_PROTECTION_STATUS");
3990Sstevel@tonic-gate 	case SMEDIA_CNUM_SET_PROTECTION_STATUS:
4000Sstevel@tonic-gate 		return ("SMEDIA_CNUM_SET_PROTECTION_STATUS");
4010Sstevel@tonic-gate 	case SMEDIA_CNUM_RAW_READ:
4020Sstevel@tonic-gate 		return ("SMEDIA_CNUM_RAW_READ");
4030Sstevel@tonic-gate 	case SMEDIA_CNUM_RAW_WRITE:
4040Sstevel@tonic-gate 		return (" SMEDIA_CNUM_RAW_WRITE");
4050Sstevel@tonic-gate 	case SMEDIA_CNUM_FORMAT:
4060Sstevel@tonic-gate 		return ("SMEDIA_CNUM_FORMAT");
4070Sstevel@tonic-gate 	case SMEDIA_CNUM_CHECK_FORMAT_STATUS:
4080Sstevel@tonic-gate 		return ("SMEDIA_CNUM_CHECK_FORMAT_STATUS");
4090Sstevel@tonic-gate 	case SMEDIA_CNUM_EJECT:
4100Sstevel@tonic-gate 		return ("SMEDIA_CNUM_EJECT");
4110Sstevel@tonic-gate 	case SMEDIA_CNUM_REASSIGN_BLOCK:
4120Sstevel@tonic-gate 		return ("SMEDIA_CNUM_REASSIGN_BLOCK");
4130Sstevel@tonic-gate 	case SMEDIA_CNUM_SET_SHFD:
4140Sstevel@tonic-gate 		return ("SMEDIA_CNUM_SET_SHFD");
4150Sstevel@tonic-gate 	case SMEDIA_CNUM_PING:
4160Sstevel@tonic-gate 		return ("SMEDIA_CNUM_PING");
4170Sstevel@tonic-gate 	case SMEDIA_CNUM_USCSI_CMD:
4180Sstevel@tonic-gate 		return ("SMEDIA_CNUM_USCSI_CMD");
4190Sstevel@tonic-gate 	default:
4200Sstevel@tonic-gate 		return ("UNKNOWN_CNUM");
4210Sstevel@tonic-gate 	}
4220Sstevel@tonic-gate }
4230Sstevel@tonic-gate 
4240Sstevel@tonic-gate /*ARGSUSED*/
4250Sstevel@tonic-gate smserver_info *
4260Sstevel@tonic-gate smserverproc_get_serverinfo_1(void *argp, CLIENT *clnt)
4270Sstevel@tonic-gate {
4280Sstevel@tonic-gate 	(void) mutex_lock(&svcstate_lock);
4290Sstevel@tonic-gate 	svcstate = _SERVED;
4300Sstevel@tonic-gate 	(void) mutex_unlock(&svcstate_lock);
4310Sstevel@tonic-gate 	server_info.vernum = SMSERVERVERS;
4320Sstevel@tonic-gate 	server_info.status = 0;
4330Sstevel@tonic-gate 	(void) mutex_lock(&server_data.sd_init_lock);
4340Sstevel@tonic-gate 	if (server_data.sd_init_state == INIT_NOT_DONE) {
4350Sstevel@tonic-gate 		server_data.sd_init_state = INIT_IN_PROGRESS;
4360Sstevel@tonic-gate 		debug(5, "Initialising server\n");
4370Sstevel@tonic-gate 		(void) init_server(NULL);
4380Sstevel@tonic-gate 	}
4390Sstevel@tonic-gate 	if (server_data.sd_init_state != INIT_DONE) {
440*1137Sarutz 		debug(1, "init_server did not do the job. "
441*1137Sarutz 		    "init_state=%d\n", server_data.sd_init_state);
4420Sstevel@tonic-gate 		server_data.sd_init_state = INIT_NOT_DONE;
4430Sstevel@tonic-gate 		(void) mutex_unlock(&server_data.sd_init_lock);
4440Sstevel@tonic-gate 		server_info.status = -1;
4450Sstevel@tonic-gate 		return (&server_info);
4460Sstevel@tonic-gate 	}
4470Sstevel@tonic-gate 	(void) mutex_unlock(&server_data.sd_init_lock);
4480Sstevel@tonic-gate 
4490Sstevel@tonic-gate 	debug(5, "smserverproc thread %d running....\n", pthread_self());
4500Sstevel@tonic-gate 	return (&server_info);
4510Sstevel@tonic-gate }
4520Sstevel@tonic-gate 
4530Sstevel@tonic-gate /*ARGSUSED*/
4540Sstevel@tonic-gate static void
4550Sstevel@tonic-gate server_badsig_handler(int sig, siginfo_t *siginfo, void *sigctx)
4560Sstevel@tonic-gate {
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 	fatal(gettext(BADSIG_MSG), pthread_self(), sig, siginfo->si_addr,
4590Sstevel@tonic-gate 		siginfo->si_trapno,
4600Sstevel@tonic-gate 		siginfo->si_pc);
4610Sstevel@tonic-gate }
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate static int32_t
4640Sstevel@tonic-gate do_uscsi_cmd(int32_t file, struct uscsi_cmd *uscsi_cmd, int32_t	flag)
4650Sstevel@tonic-gate {
4660Sstevel@tonic-gate 	int32_t	ret_val;
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate 	/*
4690Sstevel@tonic-gate 	 * Set function flags for driver.
4700Sstevel@tonic-gate 	 */
4710Sstevel@tonic-gate 	uscsi_cmd->uscsi_flags = USCSI_ISOLATE;
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate #ifdef DEBUG
4740Sstevel@tonic-gate 	uscsi_cmd->uscsi_flags |= USCSI_DIAGNOSE;
4750Sstevel@tonic-gate #else
4760Sstevel@tonic-gate 	uscsi_cmd->uscsi_flags |= USCSI_SILENT;
4770Sstevel@tonic-gate #endif /* DEBUG */
4780Sstevel@tonic-gate 
4790Sstevel@tonic-gate 	uscsi_cmd->uscsi_flags |= flag;
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate 	errno = 0;
4820Sstevel@tonic-gate 	ret_val = ioctl(file, USCSICMD, uscsi_cmd);
4830Sstevel@tonic-gate 	if (ret_val == 0 && uscsi_cmd->uscsi_status == 0) {
4840Sstevel@tonic-gate 		return (ret_val);
4850Sstevel@tonic-gate 	}
4860Sstevel@tonic-gate 	if (!errno)
4870Sstevel@tonic-gate 		errno = EIO;
4880Sstevel@tonic-gate 	return (-1);
4890Sstevel@tonic-gate }
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate static int32_t
4920Sstevel@tonic-gate get_device_type(char *v_name)
4930Sstevel@tonic-gate {
4940Sstevel@tonic-gate 	int32_t i;
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate 	for (i = 0; i < 8; i++) {
4970Sstevel@tonic-gate 		v_name[i] = toupper(v_name[i]);
4980Sstevel@tonic-gate 	}
4990Sstevel@tonic-gate 	if (strstr(v_name, "IOMEGA")) {
5000Sstevel@tonic-gate 		return (SCSI_IOMEGA);
5010Sstevel@tonic-gate 	}
5020Sstevel@tonic-gate 	if (strstr(v_name, "FD") ||
5030Sstevel@tonic-gate 	    strstr(v_name, "LS-120")) {
5040Sstevel@tonic-gate 		return (SCSI_FLOPPY);
5050Sstevel@tonic-gate 	}
5060Sstevel@tonic-gate 	return (SCSI_GENERIC);
5070Sstevel@tonic-gate 
5080Sstevel@tonic-gate }
5090Sstevel@tonic-gate 
5100Sstevel@tonic-gate static int32_t
5110Sstevel@tonic-gate get_device_type_scsi(int32_t fd, struct scsi_inquiry *inq)
5120Sstevel@tonic-gate {
5130Sstevel@tonic-gate 	int32_t dev_type;
5140Sstevel@tonic-gate 	struct uscsi_cmd ucmd;
5150Sstevel@tonic-gate 	union scsi_cdb  cdb;
5160Sstevel@tonic-gate 	int32_t	ret_val;
5170Sstevel@tonic-gate 	char rq_data[RQ_LEN];
5180Sstevel@tonic-gate 
5190Sstevel@tonic-gate 	(void) memset((void *) inq, 0, sizeof (struct scsi_inquiry));
5200Sstevel@tonic-gate 	(void) memset((void *) &ucmd, 0, sizeof (ucmd));
5210Sstevel@tonic-gate 	(void) memset((void *) &cdb, 0, sizeof (union scsi_cdb));
5220Sstevel@tonic-gate 	cdb.scc_cmd = SCMD_INQUIRY;
5230Sstevel@tonic-gate 	FORMG0COUNT(&cdb, sizeof (struct scsi_inquiry));
5240Sstevel@tonic-gate 	ucmd.uscsi_cdb = (caddr_t)&cdb;
5250Sstevel@tonic-gate 	ucmd.uscsi_cdblen = CDB_GROUP0;
5260Sstevel@tonic-gate 	ucmd.uscsi_bufaddr = (caddr_t)inq;
5270Sstevel@tonic-gate 	ucmd.uscsi_buflen = sizeof (struct scsi_inquiry);
5280Sstevel@tonic-gate 	ucmd.uscsi_timeout = 120;	/* If 0, HBA hangs forever */
5290Sstevel@tonic-gate 	ucmd.uscsi_rqlen = RQ_LEN;
5300Sstevel@tonic-gate 	ucmd.uscsi_rqbuf = rq_data;
5310Sstevel@tonic-gate 	ret_val = do_uscsi_cmd(fd, &ucmd, USCSI_READ|USCSI_RQENABLE);
5320Sstevel@tonic-gate 	if (ret_val || ucmd.uscsi_status) {
533*1137Sarutz 		debug(5, "INQUIRY failed: rv = %d  uscsi_status = "
534*1137Sarutz 		    "%d  errno = %d\n", ret_val, ucmd.uscsi_status, errno);
5350Sstevel@tonic-gate 		return (-1);
5360Sstevel@tonic-gate 	}
5370Sstevel@tonic-gate 
5380Sstevel@tonic-gate 	dev_type = get_device_type(inq->inq_vid);
5390Sstevel@tonic-gate 
5400Sstevel@tonic-gate 	debug(5, "dev_type %d\n", dev_type);
5410Sstevel@tonic-gate 	return (dev_type);
5420Sstevel@tonic-gate 
5430Sstevel@tonic-gate }
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate static int32_t
5460Sstevel@tonic-gate get_media_capacity(int32_t fd, uint32_t *capacity, uint32_t *blocksize)
5470Sstevel@tonic-gate {
5480Sstevel@tonic-gate 	struct uscsi_cmd ucmd;
5490Sstevel@tonic-gate 	uchar_t cdb[12];
5500Sstevel@tonic-gate 	int32_t ret_val;
5510Sstevel@tonic-gate 	uchar_t data[20];
5520Sstevel@tonic-gate 	char rq_data[RQ_LEN];
5530Sstevel@tonic-gate 
5540Sstevel@tonic-gate 	debug(5, "get_media_capacity:\n");
5550Sstevel@tonic-gate 
5560Sstevel@tonic-gate 	(void) memset((void *)&data, 0, sizeof (data));
5570Sstevel@tonic-gate 	(void) memset((void *)&ucmd, 0, sizeof (ucmd));
5580Sstevel@tonic-gate 	(void) memset((void *)&cdb, 0, sizeof (cdb));
5590Sstevel@tonic-gate 
5600Sstevel@tonic-gate 	/* retrieve size discriptor of inserted media */
5610Sstevel@tonic-gate 	cdb[0] = SCMD_READ_FORMAT_CAP;
5620Sstevel@tonic-gate 	cdb[8] = 0x14;  /* data size */
5630Sstevel@tonic-gate 
5640Sstevel@tonic-gate 	/* Fill in the USCSI fields */
5650Sstevel@tonic-gate 	ucmd.uscsi_cdb = (caddr_t)&cdb;
5660Sstevel@tonic-gate 	ucmd.uscsi_cdblen = CDB_GROUP5;
5670Sstevel@tonic-gate 	ucmd.uscsi_bufaddr = (caddr_t)data;
5680Sstevel@tonic-gate 	ucmd.uscsi_buflen = sizeof (data);
5690Sstevel@tonic-gate 	ucmd.uscsi_timeout = 120;
5700Sstevel@tonic-gate 	ucmd.uscsi_rqlen = RQ_LEN;
5710Sstevel@tonic-gate 	ucmd.uscsi_rqbuf = rq_data;
5720Sstevel@tonic-gate 	ret_val = do_uscsi_cmd(fd, &ucmd, USCSI_READ|USCSI_RQENABLE);
5730Sstevel@tonic-gate 
5740Sstevel@tonic-gate 	if (ret_val || ucmd.uscsi_status) {
5750Sstevel@tonic-gate 		debug(5, "Retrieving media info failed: %d - %d\n", ret_val,
5760Sstevel@tonic-gate 		    ucmd.uscsi_status);
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate 		if ((rq_data[2] == KEY_DATA_PROTECT) && (rq_data[12] == 0x30) &&
5790Sstevel@tonic-gate 		    (rq_data[13] == 0)) {
5800Sstevel@tonic-gate 			(void) debug(1, "Invalid command for media\n");
5810Sstevel@tonic-gate 			errno = EINVAL;
5820Sstevel@tonic-gate 		}
5830Sstevel@tonic-gate 		return (-1);
5840Sstevel@tonic-gate 	}
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate 	/* No media, bail out */
5870Sstevel@tonic-gate 	if (data[8] == 0x3) {
5880Sstevel@tonic-gate 		(void) debug(5, "no media in drive\n");
5890Sstevel@tonic-gate 		return (-1);
5900Sstevel@tonic-gate 	}
5910Sstevel@tonic-gate 
5920Sstevel@tonic-gate 	/*
5930Sstevel@tonic-gate 	 * Generate capacity and blocksize information
5940Sstevel@tonic-gate 	 */
5950Sstevel@tonic-gate 
5960Sstevel@tonic-gate 	*capacity =  (uint32_t)((data[4] << 24) + (data[5] << 16) +
5970Sstevel@tonic-gate 	    (data[6] << 8) + data[7]);
5980Sstevel@tonic-gate 
5990Sstevel@tonic-gate 	debug(1, "capacity is %x %x %x %x = %x", data[4], data[5], data[6],
6000Sstevel@tonic-gate 	    data[7], *capacity);
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate 	*blocksize = (uint32_t)((data[9] << 16) + (data[10] << 8) + data[11]);
6030Sstevel@tonic-gate 
6040Sstevel@tonic-gate 	return (0);
6050Sstevel@tonic-gate }
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate static int32_t
6080Sstevel@tonic-gate scsi_zip_format(int32_t fd, uint_t flavor, uint_t mode)
6090Sstevel@tonic-gate {
6100Sstevel@tonic-gate 	struct uscsi_cmd ucmd;
6110Sstevel@tonic-gate 	struct scsi_inquiry inq;
6120Sstevel@tonic-gate 	uchar_t cdb[12];
6130Sstevel@tonic-gate 	int32_t   ret_val;
6140Sstevel@tonic-gate 	uchar_t data[4];
6150Sstevel@tonic-gate 	uint32_t rc_data[2];
6160Sstevel@tonic-gate 	char rq_data[RQ_LEN];
6170Sstevel@tonic-gate 	uint32_t capacity;
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate 	if ((mode != SM_FORMAT_IMMEDIATE) &&
6210Sstevel@tonic-gate 		(mode != SM_FORMAT_BLOCKED)) {
6220Sstevel@tonic-gate 		errno = ENOTSUP;
6230Sstevel@tonic-gate 		return (ENOTSUP);
6240Sstevel@tonic-gate 	}
6250Sstevel@tonic-gate 	/*
6260Sstevel@tonic-gate 	 * Do an inquiry and try to figure out if it an
6270Sstevel@tonic-gate 	 * IOMEGA JAZ 2GB device.
6280Sstevel@tonic-gate 	 */
6290Sstevel@tonic-gate 
6300Sstevel@tonic-gate 	(void) memset((void *) &inq, 0, sizeof (inq));
6310Sstevel@tonic-gate 	(void) memset((void *) &ucmd, 0, sizeof (ucmd));
6320Sstevel@tonic-gate 	(void) memset((void *) &cdb, 0, sizeof (cdb));
6330Sstevel@tonic-gate 	(void) memset((void *) &rq_data, 0, sizeof (rq_data));
6340Sstevel@tonic-gate 	cdb[0] = SCMD_INQUIRY;
6350Sstevel@tonic-gate 	cdb[4] = sizeof (inq);
6360Sstevel@tonic-gate 	ucmd.uscsi_cdb = (caddr_t)&cdb;
6370Sstevel@tonic-gate 	ucmd.uscsi_cdblen = CDB_GROUP0;
6380Sstevel@tonic-gate 	ucmd.uscsi_bufaddr = (caddr_t)&inq;
6390Sstevel@tonic-gate 	ucmd.uscsi_buflen = sizeof (inq);
6400Sstevel@tonic-gate 	ucmd.uscsi_timeout = 120;	/* If 0, HBA hangs forever */
6410Sstevel@tonic-gate 	ucmd.uscsi_rqlen = RQ_LEN;
6420Sstevel@tonic-gate 	ucmd.uscsi_rqbuf = rq_data;
6430Sstevel@tonic-gate 	ret_val = do_uscsi_cmd(fd, &ucmd, USCSI_READ|USCSI_RQENABLE);
6440Sstevel@tonic-gate 	if (ret_val || ucmd.uscsi_status) {
6450Sstevel@tonic-gate 		debug(5, "inquiry failed: %d - %d errno = %d\n",
6460Sstevel@tonic-gate 			ret_val, ucmd.uscsi_status, errno);
6470Sstevel@tonic-gate 		return (ucmd.uscsi_status);
6480Sstevel@tonic-gate 	}
6490Sstevel@tonic-gate 
6500Sstevel@tonic-gate 	(void) memset((void *) &rc_data, 0, sizeof (rc_data));
6510Sstevel@tonic-gate 	(void) memset((void *) &ucmd, 0, sizeof (ucmd));
6520Sstevel@tonic-gate 	(void) memset((void *) &cdb, 0, sizeof (cdb));
6530Sstevel@tonic-gate 	cdb[0] = SCMD_READ_CAPACITY;
6540Sstevel@tonic-gate 	ucmd.uscsi_cdb = (caddr_t)&cdb;
6550Sstevel@tonic-gate 	ucmd.uscsi_cdblen = CDB_GROUP1;
6560Sstevel@tonic-gate 	ucmd.uscsi_bufaddr = (caddr_t)&rc_data;
6570Sstevel@tonic-gate 	ucmd.uscsi_buflen = sizeof (rc_data);
6580Sstevel@tonic-gate 	ucmd.uscsi_timeout = 120;	/* If 0, HBA hangs forever */
6590Sstevel@tonic-gate 
6600Sstevel@tonic-gate 	ret_val = do_uscsi_cmd(fd, &ucmd, USCSI_READ);
6610Sstevel@tonic-gate 	if (ret_val || ucmd.uscsi_status) {
6620Sstevel@tonic-gate 		debug(5, "Read capacity : %d - %d errno = %d\n",
6630Sstevel@tonic-gate 			ret_val, ucmd.uscsi_status, errno);
6640Sstevel@tonic-gate 		return (ucmd.uscsi_status);
6650Sstevel@tonic-gate 	}
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate 	capacity = ntohl(rc_data[0]);
6680Sstevel@tonic-gate 
6690Sstevel@tonic-gate 	(void) memset((void *)&data, 0, sizeof (data));
6700Sstevel@tonic-gate 	(void) memset((void *)&ucmd, 0, sizeof (ucmd));
6710Sstevel@tonic-gate 	(void) memset((void *)&cdb, 0, sizeof (cdb));
6720Sstevel@tonic-gate 	cdb[0] =  SCMD_FORMAT;
6730Sstevel@tonic-gate 	/*
6740Sstevel@tonic-gate 	 * Defect list sent by initiator is a complete list of defects.
6750Sstevel@tonic-gate 	 */
6760Sstevel@tonic-gate 	cdb[1] = (FMTDATA | CMPLIST);
6770Sstevel@tonic-gate 	/*
6780Sstevel@tonic-gate 	 * Target should examine the setting of the DPRY, DCRT, STPF, IP
6790Sstevel@tonic-gate 	 * and DSP bits.
6800Sstevel@tonic-gate 	 */
6810Sstevel@tonic-gate 	data[1] = FOV;
6820Sstevel@tonic-gate 
6830Sstevel@tonic-gate 	switch (flavor) {
6840Sstevel@tonic-gate 		case SM_FORMAT_QUICK :
6850Sstevel@tonic-gate 			/*
6860Sstevel@tonic-gate 			 * Target should not perform any vendor specific
6870Sstevel@tonic-gate 			 * medium certification process or format verification
6880Sstevel@tonic-gate 			 */
6890Sstevel@tonic-gate 			data[1] = (FOV | DCRT);
6900Sstevel@tonic-gate 			/*
6910Sstevel@tonic-gate 			 * Defect list sent is an addition to the existing
6920Sstevel@tonic-gate 			 * list of defects.
6930Sstevel@tonic-gate 			 */
6940Sstevel@tonic-gate 			cdb[1] =  FMTDATA;
6950Sstevel@tonic-gate 			break;
6960Sstevel@tonic-gate 		case SM_FORMAT_FORCE :
6970Sstevel@tonic-gate 			if (strstr(inq.inq_pid, "jaz")) {
6980Sstevel@tonic-gate 				debug(1,
6990Sstevel@tonic-gate 				"LONG Format of JAZ media not supported\n");
7000Sstevel@tonic-gate 				errno = ENOTSUP;
7010Sstevel@tonic-gate 				return (ENOTSUP);
7020Sstevel@tonic-gate 			}
7030Sstevel@tonic-gate 			/*
7040Sstevel@tonic-gate 			 * Formatting a write-protected or read/write
7050Sstevel@tonic-gate 			 * protected cartridge is allowed.
7060Sstevel@tonic-gate 			 * This is a vendor specific Format Option.
7070Sstevel@tonic-gate 			 */
7080Sstevel@tonic-gate 			cdb[2] = 0x20;
7090Sstevel@tonic-gate 			break;
7100Sstevel@tonic-gate 		case SM_FORMAT_LONG :
7110Sstevel@tonic-gate 			if (strstr(inq.inq_pid, "jaz")) {
7120Sstevel@tonic-gate 				debug(1,
7130Sstevel@tonic-gate 				"LONG Format of JAZ media not supported\n");
7140Sstevel@tonic-gate 				errno = ENOTSUP;
7150Sstevel@tonic-gate 				return (ENOTSUP);
7160Sstevel@tonic-gate 			}
7170Sstevel@tonic-gate 			/*
7180Sstevel@tonic-gate 			 * Defect list sent is an addition to the existing
7190Sstevel@tonic-gate 			 * list of defects.
7200Sstevel@tonic-gate 			 */
7210Sstevel@tonic-gate 			cdb[1] = FMTDATA;
7220Sstevel@tonic-gate 			break;
7230Sstevel@tonic-gate 		default :
7240Sstevel@tonic-gate 			debug(1, "Format option %d not supported!!\n",
7250Sstevel@tonic-gate 			flavor);
7260Sstevel@tonic-gate 			errno = ENOTSUP;
7270Sstevel@tonic-gate 			return (ENOTSUP);
7280Sstevel@tonic-gate 	}
7290Sstevel@tonic-gate 
7300Sstevel@tonic-gate 	if (mode == SM_FORMAT_IMMEDIATE) {
7310Sstevel@tonic-gate 		data[1] |= IMMED;
7320Sstevel@tonic-gate 		debug(5, "immediate_flag set\n");
7330Sstevel@tonic-gate 	}
7340Sstevel@tonic-gate 
7350Sstevel@tonic-gate 	ucmd.uscsi_cdb = (caddr_t)&cdb;
7360Sstevel@tonic-gate 	debug(5, "cdb: %x ", cdb[0]);
7370Sstevel@tonic-gate 	debug(5, "%x %x ", cdb[1], cdb[2]);
7380Sstevel@tonic-gate 	debug(5, "%x %x %x\n", cdb[3], cdb[4], cdb[5]);
7390Sstevel@tonic-gate 	debug(5, "data: %x %x %x %x\n", data[0], data[1], data[2], data[3]);
7400Sstevel@tonic-gate 
7410Sstevel@tonic-gate 	ucmd.uscsi_cdblen = CDB_GROUP0;
7420Sstevel@tonic-gate 	ucmd.uscsi_bufaddr = (caddr_t)data;
7430Sstevel@tonic-gate 	ucmd.uscsi_buflen = sizeof (data);
7440Sstevel@tonic-gate 	ucmd.uscsi_timeout = FORMAT_TIMEOUT(capacity);
7450Sstevel@tonic-gate 	ucmd.uscsi_rqlen = RQ_LEN;
7460Sstevel@tonic-gate 	ucmd.uscsi_rqbuf = rq_data;
7470Sstevel@tonic-gate 	ret_val = do_uscsi_cmd(fd, &ucmd, USCSI_WRITE|USCSI_RQENABLE);
7480Sstevel@tonic-gate 	if (ret_val || ucmd.uscsi_status) {
7490Sstevel@tonic-gate 		debug(5, "Format failed : %d - uscsi_status = %d errno = %d\n",
7500Sstevel@tonic-gate 			ret_val,
7510Sstevel@tonic-gate 			ucmd.uscsi_status, errno);
7520Sstevel@tonic-gate 		if ((rq_data[2] == KEY_DATA_PROTECT) ||
7530Sstevel@tonic-gate 			(rq_data[2] == KEY_ILLEGAL_REQUEST))
7540Sstevel@tonic-gate 			errno = EINVAL;
7550Sstevel@tonic-gate 		if ((rq_data[2] == KEY_MEDIUM_ERROR) ||
7560Sstevel@tonic-gate 			(rq_data[2] == KEY_HARDWARE_ERROR))
7570Sstevel@tonic-gate 			errno = EIO;
7580Sstevel@tonic-gate 		return (errno);
7590Sstevel@tonic-gate 	}
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate 	return (0);
7620Sstevel@tonic-gate }
7630Sstevel@tonic-gate 
7640Sstevel@tonic-gate static int32_t
7650Sstevel@tonic-gate scsi_ls120_format(uint_t fd, uint_t flavor, uint32_t capacity,
7660Sstevel@tonic-gate     uint32_t blocksize)
7670Sstevel@tonic-gate {
7680Sstevel@tonic-gate 	struct uscsi_cmd ucmd;
7690Sstevel@tonic-gate 	uchar_t cdb[12];
7700Sstevel@tonic-gate 	int32_t ret_val;
7710Sstevel@tonic-gate 	uchar_t data[12];
7720Sstevel@tonic-gate 	char	rq_data[RQ_LEN];
7730Sstevel@tonic-gate 
7740Sstevel@tonic-gate 	debug(5, "scsi_ls120_format:\n");
7750Sstevel@tonic-gate 
7760Sstevel@tonic-gate 	(void) memset((void *) &ucmd, 0, sizeof (ucmd));
7770Sstevel@tonic-gate 	(void) memset((void *) &cdb, 0, sizeof (cdb));
7780Sstevel@tonic-gate 	(void) memset((void *) &rq_data, 0, sizeof (rq_data));
7790Sstevel@tonic-gate 
7800Sstevel@tonic-gate 	cdb[0] = SCMD_FORMAT;
7810Sstevel@tonic-gate 	cdb[1] = (FMTDATA | 0x7);
7820Sstevel@tonic-gate 	cdb[8] = 0x0C; /* parameter list length */
7830Sstevel@tonic-gate 
7840Sstevel@tonic-gate 	data[1] = 0x80;
7850Sstevel@tonic-gate 	data[3] = 0x08;
7860Sstevel@tonic-gate 
7870Sstevel@tonic-gate 
7880Sstevel@tonic-gate 	data[4] = (capacity >> 24) & 0xff;
7890Sstevel@tonic-gate 	data[5] = (capacity >> 16) & 0xff;
7900Sstevel@tonic-gate 	data[6] = (capacity >> 8) & 0xff;
7910Sstevel@tonic-gate 	data[7] = capacity & 0xff;
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate 
7940Sstevel@tonic-gate 	data[9] =  (blocksize >> 16) & 0xff;
7950Sstevel@tonic-gate 	data[10] = (blocksize >> 8) & 0xff;
7960Sstevel@tonic-gate 	data[11] = blocksize & 0xff;
7970Sstevel@tonic-gate 
7980Sstevel@tonic-gate 	debug(5, "cdb: %x %x %x ... %x", cdb[0], cdb[1], cdb[2], cdb[8]);
7990Sstevel@tonic-gate 	debug(5, "data: %x %x %x %x\n", data[0], data[1], data[2], data[3]);
8000Sstevel@tonic-gate 	debug(5, "    : %x %x %x %x\n", data[4], data[5], data[6], data[7]);
8010Sstevel@tonic-gate 	debug(5, "    : %x %x %x %x\n", data[8], data[9], data[10], data[11]);
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate 	switch (flavor) {
8040Sstevel@tonic-gate 		case SM_FORMAT_QUICK :
8050Sstevel@tonic-gate 			debug(1, "Format not supported\n");
8060Sstevel@tonic-gate 			errno = ENOTSUP;
8070Sstevel@tonic-gate 			return (-1);
8080Sstevel@tonic-gate 		case SM_FORMAT_FORCE :
8090Sstevel@tonic-gate 			break;
8100Sstevel@tonic-gate 		case SM_FORMAT_LONG :
8110Sstevel@tonic-gate 			break;
8120Sstevel@tonic-gate 		default :
8130Sstevel@tonic-gate 			debug(1, "Format option not specified!!\n");
8140Sstevel@tonic-gate 			errno = ENOTSUP;
8150Sstevel@tonic-gate 			return (-1);
8160Sstevel@tonic-gate 	}
8170Sstevel@tonic-gate 
8180Sstevel@tonic-gate 	ucmd.uscsi_cdb = (caddr_t)&cdb;
8190Sstevel@tonic-gate 
8200Sstevel@tonic-gate 
8210Sstevel@tonic-gate 	ucmd.uscsi_cdblen = CDB_GROUP5;
8220Sstevel@tonic-gate 	ucmd.uscsi_bufaddr = (caddr_t)data;
8230Sstevel@tonic-gate 	ucmd.uscsi_buflen = sizeof (data);
8240Sstevel@tonic-gate 	ucmd.uscsi_timeout = 0x12c0;
8250Sstevel@tonic-gate 	ucmd.uscsi_rqlen = RQ_LEN;
8260Sstevel@tonic-gate 	ucmd.uscsi_rqbuf = rq_data;
8270Sstevel@tonic-gate 	(void) fflush(stdout);
8280Sstevel@tonic-gate 
8290Sstevel@tonic-gate 	ret_val = do_uscsi_cmd(fd, &ucmd, USCSI_WRITE|USCSI_RQENABLE);
8300Sstevel@tonic-gate 	if (ret_val || ucmd.uscsi_status) {
8310Sstevel@tonic-gate 		debug(1, "Format failed failed: %d - %d\n", ret_val,
8320Sstevel@tonic-gate 		    ucmd.uscsi_status);
8330Sstevel@tonic-gate 
8340Sstevel@tonic-gate 		if ((rq_data[2] == KEY_DATA_PROTECT) &&
8350Sstevel@tonic-gate 		    (rq_data[12] == 0x30) && (rq_data[13] == 0)) {
8360Sstevel@tonic-gate 
8370Sstevel@tonic-gate 			debug(1, "Invalid command for media\n");
8380Sstevel@tonic-gate 			errno = EINVAL;
8390Sstevel@tonic-gate 		}
8400Sstevel@tonic-gate 
8410Sstevel@tonic-gate 		if ((rq_data[2] == KEY_NOT_READY) && (rq_data[12] == 0x30)) {
8420Sstevel@tonic-gate 			debug(1, "Incompatible media.\n");
8430Sstevel@tonic-gate 			errno = EINVAL;
8440Sstevel@tonic-gate 		}
8450Sstevel@tonic-gate 
8460Sstevel@tonic-gate 		return (-1);
8470Sstevel@tonic-gate 	}
8480Sstevel@tonic-gate 
8490Sstevel@tonic-gate 	return (0);
8500Sstevel@tonic-gate }
8510Sstevel@tonic-gate 
8520Sstevel@tonic-gate static int32_t
8530Sstevel@tonic-gate scsi_format(int32_t fd, uint_t flavor, uint_t mode)
8540Sstevel@tonic-gate {
8550Sstevel@tonic-gate 	struct uscsi_cmd ucmd;
8560Sstevel@tonic-gate 	struct scsi_inquiry inq;
8570Sstevel@tonic-gate 	uchar_t cdb[12];
8580Sstevel@tonic-gate 	int32_t   ret_val;
8590Sstevel@tonic-gate 	uchar_t data[4];
8600Sstevel@tonic-gate 	char rq_data[RQ_LEN];
8610Sstevel@tonic-gate 	uint32_t rc_data[2];
8620Sstevel@tonic-gate 	uint32_t capacity;
8630Sstevel@tonic-gate 
8640Sstevel@tonic-gate 
8650Sstevel@tonic-gate 
8660Sstevel@tonic-gate 	if ((mode != SM_FORMAT_IMMEDIATE) &&
8670Sstevel@tonic-gate 		(mode != SM_FORMAT_BLOCKED)) {
8680Sstevel@tonic-gate 		errno = ENOTSUP;
8690Sstevel@tonic-gate 		return (-1);
8700Sstevel@tonic-gate 	}
8710Sstevel@tonic-gate 
8720Sstevel@tonic-gate 	/*
8730Sstevel@tonic-gate 	 * Do an inquiry and try to figure out if it an
8740Sstevel@tonic-gate 	 * IOMEGA JAZ 2GB device.
8750Sstevel@tonic-gate 	 */
8760Sstevel@tonic-gate 
8770Sstevel@tonic-gate 	(void) memset((void *) &inq, 0, sizeof (inq));
8780Sstevel@tonic-gate 	(void) memset((void *) &ucmd, 0, sizeof (ucmd));
8790Sstevel@tonic-gate 	(void) memset((void *) &cdb, 0, sizeof (cdb));
8800Sstevel@tonic-gate 	(void) memset((void *) &rq_data, 0, sizeof (rq_data));
8810Sstevel@tonic-gate 	cdb[0] = SCMD_INQUIRY;
8820Sstevel@tonic-gate 	cdb[4] = sizeof (inq);
8830Sstevel@tonic-gate 	ucmd.uscsi_cdb = (caddr_t)&cdb;
8840Sstevel@tonic-gate 	ucmd.uscsi_cdblen = CDB_GROUP0;
8850Sstevel@tonic-gate 	ucmd.uscsi_bufaddr = (caddr_t)&inq;
8860Sstevel@tonic-gate 	ucmd.uscsi_buflen = sizeof (inq);
8870Sstevel@tonic-gate 	ucmd.uscsi_timeout = 120;	/* If 0, HBA hangs forever */
8880Sstevel@tonic-gate 	ucmd.uscsi_rqlen = RQ_LEN;
8890Sstevel@tonic-gate 	ucmd.uscsi_rqbuf = rq_data;
8900Sstevel@tonic-gate 	ret_val = do_uscsi_cmd(fd, &ucmd, USCSI_READ|USCSI_RQENABLE);
8910Sstevel@tonic-gate 	if (ret_val || ucmd.uscsi_status) {
8920Sstevel@tonic-gate 		debug(5, "inquiry failed: %d - %d errno = %d\n",
8930Sstevel@tonic-gate 			ret_val, ucmd.uscsi_status, errno);
8940Sstevel@tonic-gate 		return (ucmd.uscsi_status);
8950Sstevel@tonic-gate 	}
8960Sstevel@tonic-gate 
8970Sstevel@tonic-gate 	(void) memset((void *) &rc_data, 0, sizeof (rc_data));
8980Sstevel@tonic-gate 	(void) memset((void *) &ucmd, 0, sizeof (ucmd));
8990Sstevel@tonic-gate 	(void) memset((void *) &cdb, 0, sizeof (cdb));
9000Sstevel@tonic-gate 	cdb[0] = SCMD_READ_CAPACITY;
9010Sstevel@tonic-gate 	ucmd.uscsi_cdb = (caddr_t)&cdb;
9020Sstevel@tonic-gate 	ucmd.uscsi_cdblen = CDB_GROUP1;
9030Sstevel@tonic-gate 	ucmd.uscsi_bufaddr = (caddr_t)&rc_data;
9040Sstevel@tonic-gate 	ucmd.uscsi_buflen = sizeof (rc_data);
9050Sstevel@tonic-gate 	ucmd.uscsi_timeout = 120;	/* If 0, HBA hangs forever */
9060Sstevel@tonic-gate 
9070Sstevel@tonic-gate 	ret_val = do_uscsi_cmd(fd, &ucmd, USCSI_READ);
9080Sstevel@tonic-gate 	if (ret_val || ucmd.uscsi_status) {
9090Sstevel@tonic-gate 		debug(5, "Read capacity : %d - %d errno = %d\n",
9100Sstevel@tonic-gate 			ret_val, ucmd.uscsi_status, errno);
9110Sstevel@tonic-gate 		return (ucmd.uscsi_status);
9120Sstevel@tonic-gate 	}
9130Sstevel@tonic-gate 
9140Sstevel@tonic-gate 	capacity = ntohl(rc_data[0]);
9150Sstevel@tonic-gate 
9160Sstevel@tonic-gate 	(void) memset((void *)&data, 0, sizeof (data));
9170Sstevel@tonic-gate 	(void) memset((void *)&ucmd, 0, sizeof (ucmd));
9180Sstevel@tonic-gate 	(void) memset((void *)&cdb, 0, sizeof (cdb));
9190Sstevel@tonic-gate 	cdb[0] =  SCMD_FORMAT;
9200Sstevel@tonic-gate 	/*
9210Sstevel@tonic-gate 	 * Defect list sent is an addition to the existing
9220Sstevel@tonic-gate 	 * list of defects.
9230Sstevel@tonic-gate 	 */
9240Sstevel@tonic-gate 	cdb[1] =  FMTDATA;
9250Sstevel@tonic-gate 	/*
9260Sstevel@tonic-gate 	 * Target should examine the setting of the DPRY, DCRT, STPF, IP
9270Sstevel@tonic-gate 	 * and DSP bits.
9280Sstevel@tonic-gate 	 */
9290Sstevel@tonic-gate 	data[1] = FOV;
9300Sstevel@tonic-gate 
9310Sstevel@tonic-gate 	if (mode == SM_FORMAT_IMMEDIATE) {
9320Sstevel@tonic-gate 		debug(5,
9330Sstevel@tonic-gate 	"SM_FORMAT_IMMEDIATE specified ignored. Performing a long format!\n");
9340Sstevel@tonic-gate 	}
9350Sstevel@tonic-gate 
9360Sstevel@tonic-gate 	switch (flavor) {
9370Sstevel@tonic-gate 		case SM_FORMAT_LONG :
9380Sstevel@tonic-gate 			if (strstr(inq.inq_pid, "jaz")) {
9390Sstevel@tonic-gate 				debug(1,
9400Sstevel@tonic-gate 				"LONG Format of JAZ media not supported\n");
9410Sstevel@tonic-gate 				errno = ENOTSUP;
9420Sstevel@tonic-gate 				return (ENOTSUP);
9430Sstevel@tonic-gate 			}
9440Sstevel@tonic-gate 			/*
9450Sstevel@tonic-gate 			 * Defect list sent is an addition to the existing
9460Sstevel@tonic-gate 			 * list of defects.
9470Sstevel@tonic-gate 			 */
9480Sstevel@tonic-gate 			cdb[1] = FMTDATA;
9490Sstevel@tonic-gate 			break;
9500Sstevel@tonic-gate 		default :
9510Sstevel@tonic-gate 			debug(1, "Format option %d  not supported!!\n",
9520Sstevel@tonic-gate 			flavor);
9530Sstevel@tonic-gate 			errno = ENOTSUP;
9540Sstevel@tonic-gate 			return (ENOTSUP);
9550Sstevel@tonic-gate 	}
9560Sstevel@tonic-gate 
9570Sstevel@tonic-gate 
9580Sstevel@tonic-gate 	ucmd.uscsi_cdb = (caddr_t)&cdb;
9590Sstevel@tonic-gate 	ucmd.uscsi_cdblen = CDB_GROUP0;
9600Sstevel@tonic-gate 	ucmd.uscsi_bufaddr = (caddr_t)data;
9610Sstevel@tonic-gate 	ucmd.uscsi_buflen = sizeof (data);
9620Sstevel@tonic-gate 	ucmd.uscsi_timeout = FORMAT_TIMEOUT(capacity);
9630Sstevel@tonic-gate 	ucmd.uscsi_rqlen = RQ_LEN;
9640Sstevel@tonic-gate 	ucmd.uscsi_rqbuf = rq_data;
9650Sstevel@tonic-gate 	ret_val = do_uscsi_cmd(fd, &ucmd, USCSI_WRITE|USCSI_RQENABLE);
9660Sstevel@tonic-gate 	if (ret_val || ucmd.uscsi_status) {
9670Sstevel@tonic-gate 		debug(5, "Format failed failed: %d - %d errno = %d\n",
9680Sstevel@tonic-gate 			ret_val, ucmd.uscsi_status, errno);
9690Sstevel@tonic-gate 		return (ucmd.uscsi_status);
9700Sstevel@tonic-gate 	}
9710Sstevel@tonic-gate 
9720Sstevel@tonic-gate 	return (0);
9730Sstevel@tonic-gate }
9740Sstevel@tonic-gate 
9750Sstevel@tonic-gate static int32_t
9760Sstevel@tonic-gate scsi_media_status(int32_t fd)
9770Sstevel@tonic-gate {
9780Sstevel@tonic-gate 	struct mode_header modeh;
9790Sstevel@tonic-gate 	struct uscsi_cmd ucmd;
9800Sstevel@tonic-gate 	union scsi_cdb  cdb;
981*1137Sarutz 	int32_t ret_val;
9820Sstevel@tonic-gate 	int32_t cur_status;
9830Sstevel@tonic-gate 	char rq_data[RQ_LEN];
9840Sstevel@tonic-gate 
9850Sstevel@tonic-gate 	debug(10, "SCSI MEDIA STATUS CALLED \n");
9860Sstevel@tonic-gate 
9870Sstevel@tonic-gate 	(void) memset((void *) &modeh, 0, sizeof (modeh));
9880Sstevel@tonic-gate 	(void) memset((void *) &ucmd, 0, sizeof (ucmd));
9890Sstevel@tonic-gate 	(void) memset((void *) &cdb, 0, sizeof (union scsi_cdb));
9900Sstevel@tonic-gate 	cdb.scc_cmd = SCMD_MODE_SENSE;
9910Sstevel@tonic-gate 	FORMG0COUNT(&cdb, sizeof (modeh));
9920Sstevel@tonic-gate 	ucmd.uscsi_cdb = (caddr_t)&cdb;
9930Sstevel@tonic-gate 	ucmd.uscsi_cdblen = CDB_GROUP0;
9940Sstevel@tonic-gate 	ucmd.uscsi_bufaddr = (caddr_t)&modeh;
9950Sstevel@tonic-gate 	ucmd.uscsi_buflen = sizeof (modeh);
9960Sstevel@tonic-gate 	ucmd.uscsi_timeout = 120;	/* If 0, HBA hangs forever */
9970Sstevel@tonic-gate 	ucmd.uscsi_rqlen = RQ_LEN;
9980Sstevel@tonic-gate 	ucmd.uscsi_rqbuf = rq_data;
9990Sstevel@tonic-gate 	ret_val = do_uscsi_cmd(fd, &ucmd, USCSI_READ|USCSI_RQENABLE);
10000Sstevel@tonic-gate 	if (ret_val || ucmd.uscsi_status) {
10010Sstevel@tonic-gate 		debug(5, "Modesense failed: %d - %d errno = %d\n",
10020Sstevel@tonic-gate 			ret_val, ucmd.uscsi_status, errno);
10030Sstevel@tonic-gate 		return (-1);
10040Sstevel@tonic-gate 	}
10050Sstevel@tonic-gate 
10060Sstevel@tonic-gate 
10070Sstevel@tonic-gate 	if (modeh.device_specific & W_E_MASK) {
10080Sstevel@tonic-gate 		cur_status = SM_WRITE_PROTECT_NOPASSWD;
10090Sstevel@tonic-gate 	} else {
10100Sstevel@tonic-gate 		cur_status = SM_WRITE_PROTECT_DISABLE;
10110Sstevel@tonic-gate 	}
10120Sstevel@tonic-gate 	debug(5, "cur status %d\n", cur_status);
10130Sstevel@tonic-gate 
10140Sstevel@tonic-gate 	return (cur_status);
10150Sstevel@tonic-gate }
10160Sstevel@tonic-gate 
10170Sstevel@tonic-gate static int32_t
10180Sstevel@tonic-gate scsi_zip_media_status(int32_t fd)
10190Sstevel@tonic-gate {
10200Sstevel@tonic-gate 	struct uscsi_cmd ucmd;
10210Sstevel@tonic-gate 	uchar_t cdb[12];
10220Sstevel@tonic-gate 	int32_t	status;
10230Sstevel@tonic-gate 	int32_t mode;
10240Sstevel@tonic-gate 	uchar_t data[64];
10250Sstevel@tonic-gate 	char rq_data[RQ_LEN];
10260Sstevel@tonic-gate 
10270Sstevel@tonic-gate 	debug(10, "Getting media status\n");
10280Sstevel@tonic-gate 
10290Sstevel@tonic-gate 	(void) memset((void *)&ucmd, 0, sizeof (ucmd));
10300Sstevel@tonic-gate 	(void) memset((void *)&cdb, 0, sizeof (cdb));
10310Sstevel@tonic-gate 
10320Sstevel@tonic-gate 	cdb[0] = IOMEGA_NONSENSE_CMD;
10330Sstevel@tonic-gate 	cdb[2] = CARTRIDGE_STATUS_PAGE;
10340Sstevel@tonic-gate 	cdb[4] = ND_LENGTH;
10350Sstevel@tonic-gate 	ucmd.uscsi_cdb = (caddr_t)&cdb;
10360Sstevel@tonic-gate 	ucmd.uscsi_cdblen = CDB_GROUP0;
10370Sstevel@tonic-gate 	ucmd.uscsi_bufaddr = (caddr_t)data;
10380Sstevel@tonic-gate 	ucmd.uscsi_buflen = 64;
10390Sstevel@tonic-gate 	ucmd.uscsi_timeout = 120;	/* If 0, HBA hangs forever */
10400Sstevel@tonic-gate 	ucmd.uscsi_rqlen = RQ_LEN;
10410Sstevel@tonic-gate 	ucmd.uscsi_rqbuf = rq_data;
10420Sstevel@tonic-gate 	status = do_uscsi_cmd(fd, &ucmd, USCSI_READ|USCSI_RQENABLE);
10430Sstevel@tonic-gate 	if (status || ucmd.uscsi_status) {
1044*1137Sarutz 		debug(5, "Cartridge protect operation failed: "
1045*1137Sarutz 		    "rv = %d  uscsi_status = %d  errno = %d\n",
1046*1137Sarutz 		    status, ucmd.uscsi_status, errno);
10470Sstevel@tonic-gate 		return (-1);
10480Sstevel@tonic-gate 	}
10490Sstevel@tonic-gate 
10500Sstevel@tonic-gate 	if (data[DISK_STATUS_OFFSET + NON_SENSE_HDR_LEN] == 4) {
10510Sstevel@tonic-gate 		debug(1, "Disk not present. \n");
10520Sstevel@tonic-gate 		return (-1);
10530Sstevel@tonic-gate 	}
10540Sstevel@tonic-gate 	mode = data[PROTECT_MODE_OFFSET + NON_SENSE_HDR_LEN] & 0xF;
10550Sstevel@tonic-gate 
1056*1137Sarutz 	debug(5, "MODE 0x%x / %d.\n", mode, mode);
1057*1137Sarutz 
10580Sstevel@tonic-gate 	switch (mode) {
10590Sstevel@tonic-gate 		case UNLOCK_MODE:
10600Sstevel@tonic-gate 			status = SM_WRITE_PROTECT_DISABLE;
10610Sstevel@tonic-gate 			break;
10620Sstevel@tonic-gate 		case WRITE_PROTECT_MODE:
10630Sstevel@tonic-gate 			status = SM_WRITE_PROTECT_NOPASSWD;
10640Sstevel@tonic-gate 			break;
10650Sstevel@tonic-gate 		case PASSWD_WRITE_PROTECT_MODE:
10660Sstevel@tonic-gate 			status = SM_WRITE_PROTECT_PASSWD;
10670Sstevel@tonic-gate 			break;
10680Sstevel@tonic-gate 		case READ_WRITE_PROTECT_MODE:
10690Sstevel@tonic-gate 			status = SM_READ_WRITE_PROTECT;
10700Sstevel@tonic-gate 			break;
10710Sstevel@tonic-gate 		default :
10720Sstevel@tonic-gate 			if (mode & TEMP_UNLOCK_MODE)
10730Sstevel@tonic-gate 				status = SM_TEMP_UNLOCK_MODE;
10740Sstevel@tonic-gate 			else
10750Sstevel@tonic-gate 				status = SM_STATUS_UNKNOWN;
10760Sstevel@tonic-gate 			break;
10770Sstevel@tonic-gate 	}
10780Sstevel@tonic-gate 
10790Sstevel@tonic-gate 	debug(5, "status %d \n", status);
10800Sstevel@tonic-gate 	return (status);
10810Sstevel@tonic-gate }
10820Sstevel@tonic-gate 
1083*1137Sarutz static int32_t
10840Sstevel@tonic-gate scsi_reassign_block(int32_t fd, diskaddr_t block)
10850Sstevel@tonic-gate {
10860Sstevel@tonic-gate 	uchar_t data[8];
10870Sstevel@tonic-gate 	struct uscsi_cmd ucmd;
10880Sstevel@tonic-gate 	char cdb[12];
10890Sstevel@tonic-gate 	int32_t	ret_val;
10900Sstevel@tonic-gate 	char rq_data[RQ_LEN];
10910Sstevel@tonic-gate 
10920Sstevel@tonic-gate 	debug(5, "SCSI REASSIGN CALLED block = %lld\n", block);
10930Sstevel@tonic-gate 
10940Sstevel@tonic-gate 	(void) memset((void *) &data, 0, sizeof (data));
10950Sstevel@tonic-gate 	(void) memset((void *) &ucmd, 0, sizeof (ucmd));
10960Sstevel@tonic-gate 	(void) memset((void *) &cdb, 0, sizeof (cdb));
10970Sstevel@tonic-gate 	cdb[0] = SCMD_REASSIGN_BLOCK;
10980Sstevel@tonic-gate 	data[3] = 4;
10990Sstevel@tonic-gate 	data[4] = ((block & 0xFF000000) >> 24);
11000Sstevel@tonic-gate 	data[5] = ((block & 0xFF0000) >> 16);
11010Sstevel@tonic-gate 	data[6] = ((block & 0xFF00) >> 8);
11020Sstevel@tonic-gate 	data[7] = block & 0xFF;
11030Sstevel@tonic-gate 
11040Sstevel@tonic-gate 	ucmd.uscsi_cdb = (caddr_t)&cdb;
11050Sstevel@tonic-gate 	ucmd.uscsi_cdblen = CDB_GROUP0;
11060Sstevel@tonic-gate 	ucmd.uscsi_bufaddr = (caddr_t)data;
11070Sstevel@tonic-gate 	ucmd.uscsi_buflen = sizeof (data);
11080Sstevel@tonic-gate 	ucmd.uscsi_timeout = 120;	/* If 0, HBA hangs forever */
11090Sstevel@tonic-gate 	ucmd.uscsi_rqlen = RQ_LEN;
11100Sstevel@tonic-gate 	ucmd.uscsi_rqbuf = rq_data;
11110Sstevel@tonic-gate 	ret_val = do_uscsi_cmd(fd, &ucmd, USCSI_WRITE|USCSI_RQENABLE);
11120Sstevel@tonic-gate 	if (ret_val || ucmd.uscsi_status) {
11130Sstevel@tonic-gate 		debug(5, "Reassign block failed: %d - %d errno = %d\n",
11140Sstevel@tonic-gate 			ret_val, ucmd.uscsi_status, errno);
11150Sstevel@tonic-gate 		return (-1);
11160Sstevel@tonic-gate 	}
11170Sstevel@tonic-gate 
11180Sstevel@tonic-gate 	return (0);
11190Sstevel@tonic-gate }
11200Sstevel@tonic-gate 
1121*1137Sarutz static int32_t
11220Sstevel@tonic-gate get_mode_page(int32_t fd, uchar_t pc, uchar_t page_code,
1123*1137Sarutz     uchar_t *md_data, uchar_t data_len)
11240Sstevel@tonic-gate {
11250Sstevel@tonic-gate 	struct uscsi_cmd ucmd;
11260Sstevel@tonic-gate 	uchar_t cdb[12];
11270Sstevel@tonic-gate 	int32_t	ret_val;
11280Sstevel@tonic-gate 	char rq_data[RQ_LEN];
11290Sstevel@tonic-gate 
1130*1137Sarutz 	debug(10, "MODE SENSE(6) - page_code = 0x%x\n", page_code);
11310Sstevel@tonic-gate 
11320Sstevel@tonic-gate 	(void) memset((void *) md_data, 0, sizeof (data_len));
11330Sstevel@tonic-gate 	(void) memset((void *) &ucmd, 0, sizeof (ucmd));
11340Sstevel@tonic-gate 	(void) memset((void *) &cdb, 0, sizeof (cdb));
11350Sstevel@tonic-gate 	cdb[0] = SCMD_MODE_SENSE;
11360Sstevel@tonic-gate 	cdb[2] = (pc << 6) | page_code;
11370Sstevel@tonic-gate 	cdb[4] = data_len;
11380Sstevel@tonic-gate 
11390Sstevel@tonic-gate 	ucmd.uscsi_cdb = (caddr_t)&cdb;
11400Sstevel@tonic-gate 	ucmd.uscsi_cdblen = CDB_GROUP0;
11410Sstevel@tonic-gate 	ucmd.uscsi_bufaddr = (caddr_t)md_data;
11420Sstevel@tonic-gate 	ucmd.uscsi_buflen = data_len;
11430Sstevel@tonic-gate 	ucmd.uscsi_timeout = 120;	/* If 0, HBA hangs forever */
11440Sstevel@tonic-gate 	ucmd.uscsi_rqlen = RQ_LEN;
11450Sstevel@tonic-gate 	ucmd.uscsi_rqbuf = rq_data;
11460Sstevel@tonic-gate 	ret_val = do_uscsi_cmd(fd, &ucmd, USCSI_READ|USCSI_RQENABLE);
11470Sstevel@tonic-gate 	if (ret_val || ucmd.uscsi_status) {
11480Sstevel@tonic-gate 		debug(5, "Modesense failed: %d - %d errno = %d\n",
11490Sstevel@tonic-gate 			ret_val, ucmd.uscsi_status, errno);
11500Sstevel@tonic-gate 		return (-2);
11510Sstevel@tonic-gate 	}
11520Sstevel@tonic-gate 
11530Sstevel@tonic-gate 	return (0);
11540Sstevel@tonic-gate }
11550Sstevel@tonic-gate 
11560Sstevel@tonic-gate static int32_t
11570Sstevel@tonic-gate scsi_zip_write_protect(int32_t fd, smwp_state_t *wp)
11580Sstevel@tonic-gate {
11590Sstevel@tonic-gate 	struct uscsi_cmd ucmd;
11600Sstevel@tonic-gate 	struct scsi_inquiry inq;
11610Sstevel@tonic-gate 	uchar_t cdb[12];
11620Sstevel@tonic-gate 	int32_t	status;
11630Sstevel@tonic-gate 	int32_t new_mode;
11640Sstevel@tonic-gate 	char rq_data[RQ_LEN];
11650Sstevel@tonic-gate 	int32_t wa_bit;
11660Sstevel@tonic-gate 	char *tmp_passwd = NULL;
11670Sstevel@tonic-gate 
11680Sstevel@tonic-gate 	debug(10, "SCSI ZIP WRITE PROTECT CALLED \n");
11690Sstevel@tonic-gate 
11700Sstevel@tonic-gate 	/*
11710Sstevel@tonic-gate 	 * Do an inquiry and try to figure out if it an
11720Sstevel@tonic-gate 	 * ATAPI or SCSI device.
11730Sstevel@tonic-gate 	 */
11740Sstevel@tonic-gate 
11750Sstevel@tonic-gate 	(void) memset((void *) &inq, 0, sizeof (inq));
11760Sstevel@tonic-gate 	(void) memset((void *) &ucmd, 0, sizeof (ucmd));
11770Sstevel@tonic-gate 	(void) memset((void *) &cdb, 0, sizeof (cdb));
11780Sstevel@tonic-gate 	(void) memset((void *) &rq_data, 0, sizeof (rq_data));
11790Sstevel@tonic-gate 	cdb[0] = SCMD_INQUIRY;
11800Sstevel@tonic-gate 	cdb[4] = sizeof (inq);
11810Sstevel@tonic-gate 	ucmd.uscsi_cdb = (caddr_t)&cdb;
11820Sstevel@tonic-gate 	ucmd.uscsi_cdblen = CDB_GROUP0;
11830Sstevel@tonic-gate 	ucmd.uscsi_bufaddr = (caddr_t)&inq;
11840Sstevel@tonic-gate 	ucmd.uscsi_buflen = sizeof (inq);
11850Sstevel@tonic-gate 	ucmd.uscsi_timeout = 120;	/* If 0, HBA hangs forever */
11860Sstevel@tonic-gate 	ucmd.uscsi_rqlen = RQ_LEN;
11870Sstevel@tonic-gate 	ucmd.uscsi_rqbuf = rq_data;
11880Sstevel@tonic-gate 	status = do_uscsi_cmd(fd, &ucmd, USCSI_READ|USCSI_RQENABLE);
11890Sstevel@tonic-gate 	if (status || ucmd.uscsi_status) {
11900Sstevel@tonic-gate 		debug(5, "inquiry failed: %d - %d errno = %d\n",
11910Sstevel@tonic-gate 			status, ucmd.uscsi_status, errno);
11920Sstevel@tonic-gate 		return (-1);
11930Sstevel@tonic-gate 	}
11940Sstevel@tonic-gate 
11950Sstevel@tonic-gate 	if (inq.inq_ansi > 0) {
11960Sstevel@tonic-gate 		wa_bit = 0;
11970Sstevel@tonic-gate 		debug(5, "SCSI device\n");
11980Sstevel@tonic-gate 	} else {
11990Sstevel@tonic-gate 		wa_bit = 1;
12000Sstevel@tonic-gate 		debug(5, "ATAPI device\n");
12010Sstevel@tonic-gate 	}
12020Sstevel@tonic-gate 
12030Sstevel@tonic-gate 	switch (wp->sm_new_state) {
12040Sstevel@tonic-gate 		case SM_WRITE_PROTECT_DISABLE :
12050Sstevel@tonic-gate 			new_mode = 0x0;
12060Sstevel@tonic-gate 			break;
12070Sstevel@tonic-gate 		case SM_WRITE_PROTECT_NOPASSWD :
12080Sstevel@tonic-gate 			new_mode = 0x2;
12090Sstevel@tonic-gate 			break;
12100Sstevel@tonic-gate 		case SM_WRITE_PROTECT_PASSWD :
12110Sstevel@tonic-gate 			new_mode = 0x3;
12120Sstevel@tonic-gate 			break;
12130Sstevel@tonic-gate 		case SM_READ_WRITE_PROTECT :
12140Sstevel@tonic-gate 			new_mode = 0x5;
12150Sstevel@tonic-gate 			break;
12160Sstevel@tonic-gate 		case SM_TEMP_UNLOCK_MODE :
12170Sstevel@tonic-gate 			new_mode = 0x8;
12180Sstevel@tonic-gate 			break;
12190Sstevel@tonic-gate 		default :
12200Sstevel@tonic-gate 			debug(1, "Invalid mode 0x%x specified\n",
12210Sstevel@tonic-gate 			wp->sm_new_state);
12220Sstevel@tonic-gate 			errno = ENOTSUP;
12230Sstevel@tonic-gate 			return (-1);
12240Sstevel@tonic-gate 	}
12250Sstevel@tonic-gate 
12260Sstevel@tonic-gate 
12270Sstevel@tonic-gate 	(void) memset((void *)&ucmd, 0, sizeof (ucmd));
12280Sstevel@tonic-gate 	(void) memset((void *)&cdb, 0, sizeof (cdb));
12290Sstevel@tonic-gate 	(void) memset((void *) &rq_data, 0, sizeof (rq_data));
12300Sstevel@tonic-gate 	cdb[0] = IOMEGA_CATRIDGE_PROTECT;
12310Sstevel@tonic-gate 	cdb[1] |= new_mode;
12320Sstevel@tonic-gate 	if (wa_bit)
12330Sstevel@tonic-gate 		cdb[1] |= WA_BIT;
12340Sstevel@tonic-gate 	cdb[4] = wp->sm_passwd_len;
12350Sstevel@tonic-gate 	ucmd.uscsi_cdb = (caddr_t)&cdb;
12360Sstevel@tonic-gate 	ucmd.uscsi_cdblen = CDB_GROUP0;
12370Sstevel@tonic-gate 	if (wa_bit && (wp->sm_passwd_len & 1)) {
12380Sstevel@tonic-gate 		/*
12390Sstevel@tonic-gate 		 * Oops, ATAPI device with an odd length passwd!
12400Sstevel@tonic-gate 		 * Allocate a buffer to hold one extra byte.
12410Sstevel@tonic-gate 		 */
12420Sstevel@tonic-gate 		debug(5, "Odd len passwd for ATAPI device!\n");
12430Sstevel@tonic-gate 		errno = 0;
12440Sstevel@tonic-gate 		tmp_passwd = (char *)malloc(wp->sm_passwd_len+1);
12450Sstevel@tonic-gate 		if (tmp_passwd == NULL) {
12460Sstevel@tonic-gate 			if (errno == 0)
12470Sstevel@tonic-gate 				errno = ENOMEM;
12480Sstevel@tonic-gate 			return (-1);
12490Sstevel@tonic-gate 		}
12500Sstevel@tonic-gate 		(void) memset(tmp_passwd, 0, wp->sm_passwd_len+1);
12510Sstevel@tonic-gate 		(void) memcpy(tmp_passwd, wp->sm_passwd, wp->sm_passwd_len);
12520Sstevel@tonic-gate 		ucmd.uscsi_bufaddr = (caddr_t)tmp_passwd;
12530Sstevel@tonic-gate 		ucmd.uscsi_buflen = wp->sm_passwd_len+1;
12540Sstevel@tonic-gate 	} else {
12550Sstevel@tonic-gate 		ucmd.uscsi_bufaddr = (caddr_t)wp->sm_passwd;
12560Sstevel@tonic-gate 		ucmd.uscsi_buflen = wp->sm_passwd_len;
12570Sstevel@tonic-gate 	}
12580Sstevel@tonic-gate 	ucmd.uscsi_timeout = 120;	/* If 0, HBA hangs forever */
12590Sstevel@tonic-gate 	ucmd.uscsi_rqlen = RQ_LEN;
12600Sstevel@tonic-gate 	ucmd.uscsi_rqbuf = rq_data;
12610Sstevel@tonic-gate 	status = do_uscsi_cmd(fd, &ucmd, USCSI_WRITE|USCSI_RQENABLE);
12620Sstevel@tonic-gate 	if (tmp_passwd != NULL) {
12630Sstevel@tonic-gate 		free(tmp_passwd);
12640Sstevel@tonic-gate 	}
12650Sstevel@tonic-gate 	if (status || ucmd.uscsi_status) {
1266*1137Sarutz 		debug(5, "Cartridge-protect operation failed: rv "
1267*1137Sarutz 		    "= %d  uscsi_status = %d  errno = %d\n", status,
1268*1137Sarutz 		    ucmd.uscsi_status, errno);
1269*1137Sarutz 		if ((rq_data[2] & 0xF) == KEY_ILLEGAL_REQUEST) {
12700Sstevel@tonic-gate 			if (rq_data[12] == 0x26) {
12710Sstevel@tonic-gate 				/* Wrong passwd */
1272*1137Sarutz 				debug(5, "Protection Request with wrong "
1273*1137Sarutz 				    "passwd. errno is being set to EACCES.\n");
12740Sstevel@tonic-gate 				errno = EACCES;
12750Sstevel@tonic-gate 			}
12760Sstevel@tonic-gate 		}
12770Sstevel@tonic-gate 		return (-1);
12780Sstevel@tonic-gate 	}
12790Sstevel@tonic-gate 
12800Sstevel@tonic-gate 	return (0);
12810Sstevel@tonic-gate }
12820Sstevel@tonic-gate 
12830Sstevel@tonic-gate /*ARGSUSED*/
12840Sstevel@tonic-gate static int32_t
12850Sstevel@tonic-gate scsi_write_protect(int32_t fd, smwp_state_t *wp)
12860Sstevel@tonic-gate {
12870Sstevel@tonic-gate 	errno = ENOTSUP;
12880Sstevel@tonic-gate 	return (-1);
12890Sstevel@tonic-gate }
12900Sstevel@tonic-gate 
1291*1137Sarutz /*
1292*1137Sarutz  * This thread becomes the server-side thread used in
1293*1137Sarutz  * the implementation of a door_call between a client
1294*1137Sarutz  * and the Client Door.
1295*1137Sarutz  *
1296*1137Sarutz  * This thread is customized both by the door_server_create(3c)
1297*1137Sarutz  * function sm_door_server_create, as well as by itself.
1298*1137Sarutz  *
1299*1137Sarutz  * This thread needs to synchronize with the
1300*1137Sarutz  * main_servproc[SMEDIA_CNUM_OPEN_FD] door_call in terms of
1301*1137Sarutz  * both successful and failure scenarios.  main_servproc
1302*1137Sarutz  * locks dd_lock before calling door_create.  This thread
1303*1137Sarutz  * then attempts to lock, but will block until main_servproc
1304*1137Sarutz  * has either created all doors it requires, or until a
1305*1137Sarutz  * door_create has failed (door_create's return and the
1306*1137Sarutz  * creation of an associated thread are asynchronous).
1307*1137Sarutz  *
1308*1137Sarutz  * If door_create failed, this thread will be able to obtain
1309*1137Sarutz  * dd_lock and call pthread_exit.  If all door_create's succeed,
1310*1137Sarutz  * this thread will obtain dd_lock and commence with
1311*1137Sarutz  * customizing the thread's attributes.  door_bind is called to
1312*1137Sarutz  * bind this thread to the per-door private thread pool, and
1313*1137Sarutz  * main_servproc is cond_signal'd to avail it of this fact.
1314*1137Sarutz  *
1315*1137Sarutz  * Finally, this thread calls door_return, which causes it to
1316*1137Sarutz  * commence its lifetime as a server-side thread in implementation
1317*1137Sarutz  * of a Client Door door_call.
1318*1137Sarutz  */
13190Sstevel@tonic-gate static void *
1320*1137Sarutz sm_server_thread(void *arg)
13210Sstevel@tonic-gate {
13220Sstevel@tonic-gate 	door_data_t	*door_dp;
1323*1137Sarutz 	struct		sigaction act;
1324*1137Sarutz 	int		i;
1325*1137Sarutz 	int		err;
13260Sstevel@tonic-gate 
13270Sstevel@tonic-gate 	door_dp = (door_data_t *)arg;
13280Sstevel@tonic-gate 
13290Sstevel@tonic-gate 	if (door_dp == NULL) {
1330*1137Sarutz 		fatal("sm_server_thread[%d]: argument is NULL!!\n",
1331*1137Sarutz 		    pthread_self());
13320Sstevel@tonic-gate 		exit(-1);
13330Sstevel@tonic-gate 	}
1334*1137Sarutz 
1335*1137Sarutz 	/* Wait for Client Door to be created */
13360Sstevel@tonic-gate 	(void) mutex_lock(&door_dp->dd_lock);
1337*1137Sarutz 	if (door_dp->dd_cdoor_descriptor < 0) {
1338*1137Sarutz 		debug(5, "sm_server_thread[%d]: door_create() failed",
1339*1137Sarutz 		    pthread_self());
1340*1137Sarutz 		(void) mutex_unlock(&door_dp->dd_lock);
1341*1137Sarutz 		pthread_exit((void *)-2);
1342*1137Sarutz 	}
13430Sstevel@tonic-gate 	(void) mutex_unlock(&door_dp->dd_lock);
13440Sstevel@tonic-gate 
13450Sstevel@tonic-gate 	for (i = 0; i < N_BADSIGS; i++) {
13460Sstevel@tonic-gate 		act.sa_sigaction = server_badsig_handler;
13470Sstevel@tonic-gate 		(void) sigemptyset(&act.sa_mask);
13480Sstevel@tonic-gate 		act.sa_flags = SA_SIGINFO;
13490Sstevel@tonic-gate 		if (sigaction(badsigs[i], &act, NULL) == -1)
13500Sstevel@tonic-gate 			warning(gettext(SIGACT_FAILED), strsignal(badsigs[i]),
1351*1137Sarutz 			    strerror(errno));
13520Sstevel@tonic-gate 	}
13530Sstevel@tonic-gate 	if (sigemptyset(&door_dp->dd_newset) != 0)
13540Sstevel@tonic-gate 		warning(gettext("sigemptyset failed. errno = %d\n"),
1355*1137Sarutz 		    errno);
1356*1137Sarutz 	if ((err = pthread_sigmask(SIG_BLOCK, &door_dp->dd_newset, NULL)) != 0)
1357*1137Sarutz 		warning(gettext("pthread_sigmask failed = %d\n"), err);
1358*1137Sarutz 
1359*1137Sarutz 	/* Bind thread with pool associated with Client Door */
1360*1137Sarutz 
1361*1137Sarutz 	if (door_bind(door_dp->dd_cdoor_descriptor) < 0) {
13620Sstevel@tonic-gate 		fatal("door_bind");
13630Sstevel@tonic-gate 		exit(-1);
13640Sstevel@tonic-gate 	}
1365*1137Sarutz 	debug(5, "thr[%d] bound to Client Door[%d]", pthread_self(),
1366*1137Sarutz 	    door_dp->dd_cdoor_descriptor);
1367*1137Sarutz 
13680Sstevel@tonic-gate 	/*
1369*1137Sarutz 	 * Set these two cancellation(5) attributes.  Ensure that the
1370*1137Sarutz 	 * pthread we create has cancellation(5) DISABLED and DEFERRED,
1371*1137Sarutz 	 * as our implementation is based on this.  DEFERRED is the
1372*1137Sarutz 	 * default, but set it anyways, in case the defaults change in
1373*1137Sarutz 	 * the future.
13740Sstevel@tonic-gate 	 */
1375*1137Sarutz 	if ((err = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL)) != 0)
1376*1137Sarutz 		warning(gettext("pthread_setcancelstate(PTHREAD_CANCEL_DISABLE)"
1377*1137Sarutz 		    " failed = %d\n"), err);
1378*1137Sarutz 	if ((err = pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,
1379*1137Sarutz 	    NULL)) != 0)
1380*1137Sarutz 		warning(gettext("pthread_setcanceltype(DEFERRED) "
1381*1137Sarutz 		    "failed = %d\n"), err);
1382*1137Sarutz 
1383*1137Sarutz 	/* Inform main_servproc that door_bind() is complete. */
1384*1137Sarutz 	(void) cond_signal(&door_dp->dd_cv_bind);
1385*1137Sarutz 
13860Sstevel@tonic-gate 	/*
1387*1137Sarutz 	 * Per doors protocol, transfer control to the doors-runtime in
1388*1137Sarutz 	 * order to make this thread available to answer future door_call()'s.
13890Sstevel@tonic-gate 	 */
13900Sstevel@tonic-gate 	(void) door_return(NULL, 0, NULL, 0);
13910Sstevel@tonic-gate 	return (NULL);
13920Sstevel@tonic-gate }
13930Sstevel@tonic-gate 
1394*1137Sarutz /*
1395*1137Sarutz  * This function cleans up all per-connection resources.
1396*1137Sarutz  *
1397*1137Sarutz  * This function is called when the Client Door's service procedure
1398*1137Sarutz  * (client_servproc) is called w/ DOOR_UNREF_DATA, which is the
1399*1137Sarutz  * doors protocol convention stating that the number of file
1400*1137Sarutz  * descriptors referring to this door has dropped to one.
1401*1137Sarutz  * client_servproc is passed DOOR_UNREF_DATA because the Client Door
1402*1137Sarutz  * was door_create'd with the DOOR_UNREF bitflag.
1403*1137Sarutz  */
14040Sstevel@tonic-gate static void
1405*1137Sarutz cleanup(door_data_t *door_dp)
14060Sstevel@tonic-gate {
1407*1137Sarutz 	/* do door_revoke() of Death Door */
1408*1137Sarutz 	if (door_dp->dd_ddoor_descriptor >= 0) {
1409*1137Sarutz 		debug(1, "cleanup[%d]: door_revoke() Death Door[%d]",
1410*1137Sarutz 		    pthread_self(), door_dp->dd_ddoor_descriptor);
1411*1137Sarutz 
1412*1137Sarutz 		if (door_revoke(door_dp->dd_ddoor_descriptor) < 0) {
1413*1137Sarutz 			warning(gettext("cleanup[%d]: door_revoke() of Death "
1414*1137Sarutz 			    "Door(%d) failed = %d"), pthread_self(),
1415*1137Sarutz 			    door_dp->dd_ddoor_descriptor, errno);
1416*1137Sarutz 		} else {
1417*1137Sarutz 			door_dp->dd_ddoor_descriptor = -1;
1418*1137Sarutz 		}
14190Sstevel@tonic-gate 	}
1420*1137Sarutz 
1421*1137Sarutz 	/* release memory that is shared between client and (our) server */
1422*1137Sarutz 	if (door_dp->dd_buffd >= 0) {
1423*1137Sarutz 		debug(1, "cleanup[%d]: release shared memory", pthread_self());
14240Sstevel@tonic-gate 		(void) munmap(door_dp->dd_buf, door_dp->dd_buf_len);
14250Sstevel@tonic-gate 		(void) close(door_dp->dd_buffd);
1426*1137Sarutz 
1427*1137Sarutz 		door_dp->dd_buffd = -1;
14280Sstevel@tonic-gate 		door_dp->dd_buf = NULL;
14290Sstevel@tonic-gate 		door_dp->dd_buf_len = 0;
14300Sstevel@tonic-gate 	}
14310Sstevel@tonic-gate 
1432*1137Sarutz 	/* close the (target) device that the Client is operating on */
1433*1137Sarutz 	if (door_dp->dd_fd >= 0) {
1434*1137Sarutz 		debug(1, "cleanup[%d]: close(%d) target device", pthread_self(),
1435*1137Sarutz 		    door_dp->dd_fd);
1436*1137Sarutz 		if (close(door_dp->dd_fd) < 0) {
1437*1137Sarutz 			warning(gettext("cleanup[%d]: close() of target device"
1438*1137Sarutz 			    "failed = %d\n"), pthread_self(), errno);
1439*1137Sarutz 		}
1440*1137Sarutz 	}
1441*1137Sarutz 
1442*1137Sarutz 	/*
1443*1137Sarutz 	 * Unbind the current thread from the Client Door's private
1444*1137Sarutz 	 * thread pool.
1445*1137Sarutz 	 */
1446*1137Sarutz 	debug(1, "cleanup[%d]: door_unbind() of Client Door[%d]",
1447*1137Sarutz 	    pthread_self(), door_dp->dd_cdoor_descriptor);
1448*1137Sarutz 	if (door_unbind() < 0)
1449*1137Sarutz 		warning("door_unbind() of Client Door[%d] failed = "
1450*1137Sarutz 		    "%d", door_dp->dd_cdoor_descriptor, errno);
1451*1137Sarutz 
1452*1137Sarutz 	/* Disallow any future requests to the Client Door */
1453*1137Sarutz 	if (door_dp->dd_cdoor_descriptor >= 0) {
1454*1137Sarutz 		debug(1, "cleanup[%d]: door_revoke() Client Door[%d]",
1455*1137Sarutz 		    pthread_self(), door_dp->dd_cdoor_descriptor);
1456*1137Sarutz 
1457*1137Sarutz 		if (door_revoke(door_dp->dd_cdoor_descriptor) < 0) {
1458*1137Sarutz 			warning(gettext("cleanup[%d]: door_revoke() of "
1459*1137Sarutz 			    "Client Door[%d] failed = %d"), pthread_self(),
1460*1137Sarutz 			    door_dp->dd_cdoor_descriptor, errno);
1461*1137Sarutz 		}
14620Sstevel@tonic-gate 	}
1463*1137Sarutz 
14640Sstevel@tonic-gate 	free(door_dp);
1465*1137Sarutz 	debug(5, "cleanup[%d] ...exiting\n", pthread_self());
14660Sstevel@tonic-gate }
14670Sstevel@tonic-gate 
1468*1137Sarutz /*
1469*1137Sarutz  * This is the door_server_create(3c) function used to customize
1470*1137Sarutz  * creation of the threads used in the handling of our daemon's
1471*1137Sarutz  * door_call(3c)'s.
1472*1137Sarutz  *
1473*1137Sarutz  * This function is called synchronously as part of door_create(3c).
1474*1137Sarutz  * Note that door_create(), however, is not synchronous; it can return
1475*1137Sarutz  * with the created door file descriptor before any associated
1476*1137Sarutz  * thread has been created.  As a result, synchronization is needed
1477*1137Sarutz  * between door_create() caller and the created pthread.  This is
1478*1137Sarutz  * needed both when each activity succeeds or when either activity
1479*1137Sarutz  * fails.
1480*1137Sarutz  *
1481*1137Sarutz  * Specifically, this function ensures that each "connection"
1482*1137Sarutz  * with the client creates only one thread in the per-door,
1483*1137Sarutz  * private thread pool.  This function locks dd_threadlock and
1484*1137Sarutz  * then calls pthread_create().  If that succeeds, dd_thread
1485*1137Sarutz  * is assigned the thread id, and dd_threadlock is unlocked.
1486*1137Sarutz  * Any per-connection door_create that causes control to flow
1487*1137Sarutz  * to this function will eventually find that dd_thread is
1488*1137Sarutz  * non-zero, and control will exit this function.
1489*1137Sarutz  *
1490*1137Sarutz  * In the current implementation, the door_create for the Client Door
1491*1137Sarutz  * is called first, and the Death Door is door_create'd second.
1492*1137Sarutz  * As a result, the following function can safely make the static
1493*1137Sarutz  * assumption that the first door (within a connection) is the
1494*1137Sarutz  * Client Door.  A connection's Client Door and Death Door share
1495*1137Sarutz  * the same thread as well as the same door_data_t instance.
1496*1137Sarutz  */
14970Sstevel@tonic-gate static void
1498*1137Sarutz sm_door_server_create(door_info_t *dip)
14990Sstevel@tonic-gate {
15000Sstevel@tonic-gate 	door_data_t	*door_dp;
15010Sstevel@tonic-gate 	pthread_t	tid;
15020Sstevel@tonic-gate 	pthread_attr_t	attr;
15030Sstevel@tonic-gate 	int		ret_val;
1504*1137Sarutz 	int		err;
15050Sstevel@tonic-gate 
15060Sstevel@tonic-gate 	if (dip == NULL) {
15070Sstevel@tonic-gate 		return;
15080Sstevel@tonic-gate 	}
1509796Smathue 	door_dp = (door_data_t *)(uintptr_t)dip->di_data;
15100Sstevel@tonic-gate 
1511*1137Sarutz 	debug(10, "sm_door_server_create[%d]: entering...\n", pthread_self());
15120Sstevel@tonic-gate 
15130Sstevel@tonic-gate 	/* create one thread for this door */
15140Sstevel@tonic-gate 
15150Sstevel@tonic-gate 	(void) mutex_lock(&door_dp->dd_threadlock);
15160Sstevel@tonic-gate 
15170Sstevel@tonic-gate 	if (door_dp->dd_thread != 0) {
1518*1137Sarutz 		debug(8, "sm_door_server_create[%d]: Exiting without creating "
1519*1137Sarutz 		    "thread.\n", pthread_self());
15200Sstevel@tonic-gate 		(void) mutex_unlock(&door_dp->dd_threadlock);
15210Sstevel@tonic-gate 		return;
15220Sstevel@tonic-gate 	}
15230Sstevel@tonic-gate 
15240Sstevel@tonic-gate 	(void) pthread_attr_init(&attr);
1525*1137Sarutz 
1526*1137Sarutz 	if ((err = pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM)) != 0)
1527*1137Sarutz 		warning(gettext("pthread_attr_setscope failed = %d\n"), err);
1528*1137Sarutz 	if ((err = pthread_attr_setdetachstate(&attr,
1529*1137Sarutz 	    PTHREAD_CREATE_DETACHED)) != 0)
1530*1137Sarutz 		warning(gettext("pthread_attr_setdetachstate failed = %d\n"),
1531*1137Sarutz 		    err);
1532*1137Sarutz 
1533*1137Sarutz 	ret_val = pthread_create(&tid, &attr, sm_server_thread,
1534*1137Sarutz 	    (void *)(uintptr_t)(dip->di_data));
15350Sstevel@tonic-gate 	if (ret_val != 0) {
1536*1137Sarutz 		warning(gettext("sm_door_server_create[%d]: pthread_create "
1537*1137Sarutz 		    "failed = %d\n"), pthread_self(), ret_val);
15380Sstevel@tonic-gate 		(void) mutex_unlock(&door_dp->dd_threadlock);
15390Sstevel@tonic-gate 		(void) pthread_attr_destroy(&attr);
15400Sstevel@tonic-gate 		return;
15410Sstevel@tonic-gate 	}
15420Sstevel@tonic-gate 	(void) pthread_attr_destroy(&attr);
15430Sstevel@tonic-gate 	door_dp->dd_thread = tid;
15440Sstevel@tonic-gate 
15450Sstevel@tonic-gate 	(void) mutex_unlock(&door_dp->dd_threadlock);
1546*1137Sarutz 	debug(5, "Exiting sm_door_server_create[%d] after creating thr[%d].\n",
1547*1137Sarutz 	    pthread_self(), tid);
15480Sstevel@tonic-gate }
15490Sstevel@tonic-gate 
15500Sstevel@tonic-gate static void
15510Sstevel@tonic-gate door_ret_err(smedia_reterror_t *reterror, int32_t err)
15520Sstevel@tonic-gate {
15530Sstevel@tonic-gate 	reterror->cnum = SMEDIA_CNUM_ERROR;
15540Sstevel@tonic-gate 	reterror->errnum = err;
15550Sstevel@tonic-gate 	(void) door_return((char *)reterror, sizeof (smedia_reterror_t), 0, 0);
15560Sstevel@tonic-gate }
15570Sstevel@tonic-gate 
15580Sstevel@tonic-gate static void
15590Sstevel@tonic-gate my_door_return(char *data_ptr, size_t data_size,
15600Sstevel@tonic-gate 	door_desc_t *desc_ptr, uint_t num_desc)
15610Sstevel@tonic-gate {
15620Sstevel@tonic-gate 	(void) door_return(data_ptr, data_size, desc_ptr, num_desc);
15630Sstevel@tonic-gate }
15640Sstevel@tonic-gate 
15650Sstevel@tonic-gate static int32_t
15660Sstevel@tonic-gate raw_read(door_data_t *door_dp, smedia_services_t *req)
15670Sstevel@tonic-gate {
15680Sstevel@tonic-gate 	struct uscsi_cmd	ucmd;
15690Sstevel@tonic-gate 	union scsi_cdb		cdb;
15700Sstevel@tonic-gate 	int32_t			ret_val;
15710Sstevel@tonic-gate 	int32_t			num_sectors, sector_size;
15720Sstevel@tonic-gate 	int32_t			rc_data[2];
15730Sstevel@tonic-gate 	char			rq_data[RQ_LEN];
15740Sstevel@tonic-gate 
15750Sstevel@tonic-gate 	(void) memset((void *) &rc_data, 0, sizeof (rc_data));
15760Sstevel@tonic-gate 	(void) memset((void *) &ucmd, 0, sizeof (ucmd));
15770Sstevel@tonic-gate 	(void) memset((void *) &cdb, 0, sizeof (union scsi_cdb));
15780Sstevel@tonic-gate 
15790Sstevel@tonic-gate 	if (door_dp->dd_sector_size == 0) {
15800Sstevel@tonic-gate 		sector_size = get_sector_size(door_dp->dd_fd);
15810Sstevel@tonic-gate 		door_dp->dd_sector_size = sector_size;
15820Sstevel@tonic-gate 	} else sector_size = door_dp->dd_sector_size;
15830Sstevel@tonic-gate 
15840Sstevel@tonic-gate 	if ((req->reqraw_read.nbytes > door_dp->dd_buf_len) ||
15850Sstevel@tonic-gate 		(door_dp->dd_buf == NULL)) {
15860Sstevel@tonic-gate 		errno = EINVAL;
15870Sstevel@tonic-gate 		return (-1);
15880Sstevel@tonic-gate 	}
15890Sstevel@tonic-gate 	if ((!req->reqraw_read.nbytes) ||
15900Sstevel@tonic-gate 		(req->reqraw_read.nbytes % sector_size)) {
15910Sstevel@tonic-gate 		errno = EINVAL;
15920Sstevel@tonic-gate 		return (-1);
15930Sstevel@tonic-gate 	}
15940Sstevel@tonic-gate 
15950Sstevel@tonic-gate 	(void) memset((void *) &cdb, 0, sizeof (cdb));
15960Sstevel@tonic-gate 	num_sectors = (uint32_t)req->reqraw_read.nbytes/sector_size;
15970Sstevel@tonic-gate 
15980Sstevel@tonic-gate 	cdb.scc_cmd = SCMD_READ_G1;
15990Sstevel@tonic-gate 	FORMG1ADDR(&cdb, (uint32_t)req->reqraw_read.blockno);
16000Sstevel@tonic-gate 	FORMG1COUNT(&cdb, num_sectors);
16010Sstevel@tonic-gate 
16020Sstevel@tonic-gate 	ucmd.uscsi_cdb = (caddr_t)&cdb;
16030Sstevel@tonic-gate 	ucmd.uscsi_cdblen = CDB_GROUP1;
16040Sstevel@tonic-gate 	ucmd.uscsi_bufaddr = (caddr_t)door_dp->dd_buf;
16050Sstevel@tonic-gate 	ucmd.uscsi_buflen = (uint32_t)req->reqraw_read.nbytes;
16060Sstevel@tonic-gate 	ucmd.uscsi_timeout = 120;	/* If 0, HBA hangs forever */
16070Sstevel@tonic-gate 	ucmd.uscsi_rqlen = RQ_LEN;
16080Sstevel@tonic-gate 	ucmd.uscsi_rqbuf = rq_data;
16090Sstevel@tonic-gate 	ret_val = do_uscsi_cmd(door_dp->dd_fd,
16100Sstevel@tonic-gate 		&ucmd, USCSI_READ|USCSI_RQENABLE);
16110Sstevel@tonic-gate 	if (ret_val || ucmd.uscsi_status) {
16120Sstevel@tonic-gate 		debug(5, "read failed: %d - %d errno = %d\n",
16130Sstevel@tonic-gate 			ret_val, ucmd.uscsi_status, errno);
16140Sstevel@tonic-gate 		debug(5, "buflen = 0x%x resid = 0x%x sector size = %d\n",
16150Sstevel@tonic-gate 			ucmd.uscsi_buflen, ucmd.uscsi_resid, sector_size);
16160Sstevel@tonic-gate 		debug(5, "cdb addr: %x %x %x %x \n", cdb.g1_addr3,
16170Sstevel@tonic-gate 			cdb.g1_addr2, cdb.g1_addr1, cdb.g1_addr0);
16180Sstevel@tonic-gate 		debug(5, "cdb count: %x %x\n", cdb.g1_count1,
16190Sstevel@tonic-gate 			cdb.g1_count0);
16200Sstevel@tonic-gate 		return (-1);
16210Sstevel@tonic-gate 	}
16220Sstevel@tonic-gate 	ret_val = ucmd.uscsi_buflen - ucmd.uscsi_resid;
16230Sstevel@tonic-gate 	return (ret_val);
16240Sstevel@tonic-gate }
16250Sstevel@tonic-gate 
16260Sstevel@tonic-gate static int32_t
16270Sstevel@tonic-gate raw_write(door_data_t *door_dp, smedia_services_t *req)
16280Sstevel@tonic-gate {
16290Sstevel@tonic-gate 	struct uscsi_cmd	ucmd;
16300Sstevel@tonic-gate 	union scsi_cdb		cdb;
16310Sstevel@tonic-gate 	int32_t			ret_val;
16320Sstevel@tonic-gate 	int32_t			num_sectors, sector_size;
16330Sstevel@tonic-gate 	int32_t			rc_data[2];
16340Sstevel@tonic-gate 	char			rq_data[RQ_LEN];
16350Sstevel@tonic-gate 
16360Sstevel@tonic-gate 	(void) memset((void *) &rc_data, 0, sizeof (rc_data));
16370Sstevel@tonic-gate 	(void) memset((void *) &ucmd, 0, sizeof (ucmd));
16380Sstevel@tonic-gate 	(void) memset((void *) &cdb, 0, sizeof (union scsi_cdb));
16390Sstevel@tonic-gate 
16400Sstevel@tonic-gate 	if (door_dp->dd_sector_size == 0) {
16410Sstevel@tonic-gate 		sector_size = get_sector_size(door_dp->dd_fd);
16420Sstevel@tonic-gate 		door_dp->dd_sector_size = sector_size;
16430Sstevel@tonic-gate 	} else sector_size = door_dp->dd_sector_size;
16440Sstevel@tonic-gate 
16450Sstevel@tonic-gate 
16460Sstevel@tonic-gate 	if ((req->reqraw_write.nbytes > door_dp->dd_buf_len) ||
16470Sstevel@tonic-gate 		(door_dp->dd_buf == NULL)) {
16480Sstevel@tonic-gate 		errno = EINVAL;
16490Sstevel@tonic-gate 		return (-1);
16500Sstevel@tonic-gate 	}
16510Sstevel@tonic-gate 	if ((req->reqraw_write.nbytes % sector_size)) {
16520Sstevel@tonic-gate 		errno = EINVAL;
16530Sstevel@tonic-gate 		return (-1);
16540Sstevel@tonic-gate 	}
16550Sstevel@tonic-gate 
16560Sstevel@tonic-gate 	(void) memset((void *) &cdb, 0, sizeof (cdb));
16570Sstevel@tonic-gate 	num_sectors = (uint32_t)req->reqraw_write.nbytes/sector_size;
16580Sstevel@tonic-gate 
16590Sstevel@tonic-gate 	cdb.scc_cmd = SCMD_WRITE_G1;
16600Sstevel@tonic-gate 	FORMG1ADDR(&cdb, (uint32_t)req->reqraw_write.blockno);
16610Sstevel@tonic-gate 	FORMG1COUNT(&cdb, num_sectors);
16620Sstevel@tonic-gate 
16630Sstevel@tonic-gate 	ucmd.uscsi_cdb = (caddr_t)&cdb;
16640Sstevel@tonic-gate 	ucmd.uscsi_cdblen = CDB_GROUP1;
16650Sstevel@tonic-gate 	ucmd.uscsi_bufaddr = (caddr_t)door_dp->dd_buf;
16660Sstevel@tonic-gate 	ucmd.uscsi_buflen = (uint32_t)req->reqraw_write.nbytes;
16670Sstevel@tonic-gate 	ucmd.uscsi_timeout = 120;	/* If 0, HBA hangs forever */
16680Sstevel@tonic-gate 	ucmd.uscsi_rqlen = RQ_LEN;
16690Sstevel@tonic-gate 	ucmd.uscsi_rqbuf = rq_data;
16700Sstevel@tonic-gate 	ret_val = do_uscsi_cmd(door_dp->dd_fd,
16710Sstevel@tonic-gate 		&ucmd, USCSI_WRITE|USCSI_RQENABLE);
16720Sstevel@tonic-gate 	if (ret_val || ucmd.uscsi_status) {
16730Sstevel@tonic-gate 		debug(5, "write failed: %d - %d errno = %d\n",
16740Sstevel@tonic-gate 			ret_val, ucmd.uscsi_status, errno);
16750Sstevel@tonic-gate 		debug(5, "buflen = 0x%x resid = 0x%x sector size = %d\n",
16760Sstevel@tonic-gate 			ucmd.uscsi_buflen, ucmd.uscsi_resid, sector_size);
16770Sstevel@tonic-gate 		debug(5, "cdb addr: %x %x %x %x \n", cdb.g1_addr3,
16780Sstevel@tonic-gate 			cdb.g1_addr2, cdb.g1_addr1, cdb.g1_addr0);
16790Sstevel@tonic-gate 		debug(5, "cdb count: %x %x\n", cdb.g1_count1,
16800Sstevel@tonic-gate 			cdb.g1_count0);
16810Sstevel@tonic-gate 		return (-1);
16820Sstevel@tonic-gate 	}
16830Sstevel@tonic-gate 	ret_val = ucmd.uscsi_buflen - ucmd.uscsi_resid;
16840Sstevel@tonic-gate 	return (ret_val);
16850Sstevel@tonic-gate }
16860Sstevel@tonic-gate 
16870Sstevel@tonic-gate static int32_t
16880Sstevel@tonic-gate set_protection_status(door_data_t *door_dp, smedia_services_t *req)
16890Sstevel@tonic-gate {
16900Sstevel@tonic-gate 	int32_t			ret_val, saved_errno, status;
16910Sstevel@tonic-gate 	struct scsi_inquiry	inq;
16920Sstevel@tonic-gate 	char			vid[9];
16930Sstevel@tonic-gate 	char			pid[17];
16940Sstevel@tonic-gate 	struct passwd		*pwd;
16950Sstevel@tonic-gate 	char			uname[MAXUGNAME + 1];
16960Sstevel@tonic-gate 	char			*new_state, *old_state;
16970Sstevel@tonic-gate 
16980Sstevel@tonic-gate 	/*
16990Sstevel@tonic-gate 	 * Read the current protection state before modifiying.
17000Sstevel@tonic-gate 	 * Needed for audit purposes.
17010Sstevel@tonic-gate 	 */
17020Sstevel@tonic-gate 	switch (get_device_type_scsi(door_dp->dd_fd, &inq)) {
17030Sstevel@tonic-gate 	case SCSI_IOMEGA:
17040Sstevel@tonic-gate 		status = scsi_zip_media_status(door_dp->dd_fd);
17050Sstevel@tonic-gate 		ret_val = scsi_zip_write_protect(door_dp->dd_fd,
17060Sstevel@tonic-gate 			&req->reqset_protection_status.prot_state);
17070Sstevel@tonic-gate 		break;
17080Sstevel@tonic-gate 	case SCSI_FLOPPY:
17090Sstevel@tonic-gate 		info("Formatting floppy");
17100Sstevel@tonic-gate 		status = scsi_floppy_media_status(door_dp->dd_fd);
17110Sstevel@tonic-gate 		ret_val = scsi_floppy_write_protect(door_dp->dd_fd,
17120Sstevel@tonic-gate 			&req->reqset_protection_status.prot_state);
17130Sstevel@tonic-gate 		break;
17140Sstevel@tonic-gate 	case SCSI_GENERIC:
17150Sstevel@tonic-gate 		status = scsi_media_status(door_dp->dd_fd);
17160Sstevel@tonic-gate 		ret_val = scsi_write_protect(door_dp->dd_fd,
17170Sstevel@tonic-gate 			&req->reqset_protection_status.prot_state);
17180Sstevel@tonic-gate 		break;
17190Sstevel@tonic-gate 	}
17200Sstevel@tonic-gate 
17210Sstevel@tonic-gate 	saved_errno = errno;
17220Sstevel@tonic-gate 	new_state = xlate_state(
17230Sstevel@tonic-gate 	    req->reqset_protection_status.prot_state.sm_new_state);
17240Sstevel@tonic-gate 	old_state = xlate_state(status);
17250Sstevel@tonic-gate 
17260Sstevel@tonic-gate 	if (can_audit()) {
17270Sstevel@tonic-gate 		(void) audit_save_me(door_dp);
17280Sstevel@tonic-gate 		door_dp->audit_text[0] = 0;
17290Sstevel@tonic-gate 		door_dp->audit_text1[0] = 0;
17300Sstevel@tonic-gate 		door_dp->audit_event = AUE_smserverd;
17310Sstevel@tonic-gate 	}
17320Sstevel@tonic-gate 	(void) strlcpy(vid, inq.inq_vid, sizeof (vid));
17330Sstevel@tonic-gate 	(void) strlcpy(pid, inq.inq_pid, sizeof (pid));
17340Sstevel@tonic-gate 	if (ret_val < 0) {
17350Sstevel@tonic-gate 	    if (errno == EACCES) {
17360Sstevel@tonic-gate 		pwd = getpwuid(door_dp->dd_cred.dc_ruid);
17370Sstevel@tonic-gate 		if (pwd != NULL) {
17380Sstevel@tonic-gate 			(void) strlcpy(uname,
17390Sstevel@tonic-gate 				pwd->pw_name, MAXUGNAME);
17400Sstevel@tonic-gate 		} else uname[0] = 0;
17410Sstevel@tonic-gate 
17420Sstevel@tonic-gate 		if (can_audit()) {
17430Sstevel@tonic-gate 			(void) snprintf(door_dp->audit_text,
17440Sstevel@tonic-gate 				sizeof (door_dp->audit_text),
17450Sstevel@tonic-gate 				dgettext(TEXT_DOMAIN, "from %s to %s"),
17460Sstevel@tonic-gate 				old_state, new_state);
17470Sstevel@tonic-gate 
17480Sstevel@tonic-gate 			(void) snprintf(door_dp->audit_text1,
17490Sstevel@tonic-gate 				sizeof (door_dp->audit_text1),
17500Sstevel@tonic-gate 				"%s %s (%d,%d)", vid, pid,
17510Sstevel@tonic-gate 				(int)major(door_dp->dd_stat.st_rdev),
17520Sstevel@tonic-gate 				(int)minor(door_dp->dd_stat.st_rdev));
17530Sstevel@tonic-gate 
17540Sstevel@tonic-gate 			door_dp->audit_sorf = 1;
17550Sstevel@tonic-gate 			if (audit_audit(door_dp) == -1)
17560Sstevel@tonic-gate 			    warning("Error in writing audit info\n");
17570Sstevel@tonic-gate 		}
17580Sstevel@tonic-gate 	    } /* errno == EACCES */
17590Sstevel@tonic-gate 	    errno = saved_errno;
17600Sstevel@tonic-gate 	    return (-1);
17610Sstevel@tonic-gate 	}
17620Sstevel@tonic-gate 	if (can_audit()) {
17630Sstevel@tonic-gate 		(void) snprintf(door_dp->audit_text,
17640Sstevel@tonic-gate 			sizeof (door_dp->audit_text),
17650Sstevel@tonic-gate 			dgettext(TEXT_DOMAIN, "from %s to %s"),
17660Sstevel@tonic-gate 			old_state, new_state);
17670Sstevel@tonic-gate 
17680Sstevel@tonic-gate 		(void) snprintf(door_dp->audit_text1,
17690Sstevel@tonic-gate 			sizeof (door_dp->audit_text1),
17700Sstevel@tonic-gate 			"%s %s (%d,%d)", vid, pid,
17710Sstevel@tonic-gate 			(int)major(door_dp->dd_stat.st_rdev),
17720Sstevel@tonic-gate 			(int)minor(door_dp->dd_stat.st_rdev));
17730Sstevel@tonic-gate 
17740Sstevel@tonic-gate 		door_dp->audit_sorf = 0;
17750Sstevel@tonic-gate 		if (audit_audit(door_dp) == -1)
17760Sstevel@tonic-gate 		    warning("Error in writing audit info\n");
17770Sstevel@tonic-gate 	}
17780Sstevel@tonic-gate 	errno = saved_errno;
17790Sstevel@tonic-gate 	return (0);
17800Sstevel@tonic-gate }
17810Sstevel@tonic-gate 
17820Sstevel@tonic-gate static int32_t
1783*1137Sarutz set_shfd(door_data_t *door_dp, int32_t fd, smedia_services_t *req)
17840Sstevel@tonic-gate {
17850Sstevel@tonic-gate 	void	*fbuf;
1786*1137Sarutz 	int32_t ret_val = 0;
1787*1137Sarutz 
1788*1137Sarutz 	if ((door_dp->dd_buffd != -1) && (door_dp->dd_buf != NULL)) {
1789*1137Sarutz 		ret_val = munmap(door_dp->dd_buf, door_dp->dd_buf_len);
1790*1137Sarutz 		if (ret_val == -1)
1791*1137Sarutz 			warning(gettext("munmap failed. errno=%d\n"),
1792*1137Sarutz 			    errno);
1793*1137Sarutz 		(void) close(door_dp->dd_buffd);
1794*1137Sarutz 
1795*1137Sarutz 		door_dp->dd_buffd = -1;
1796*1137Sarutz 		door_dp->dd_buf = 0;
1797*1137Sarutz 		door_dp->dd_buf_len = 0;
17980Sstevel@tonic-gate 	}
1799*1137Sarutz 
18000Sstevel@tonic-gate 	fbuf = mmap(0, req->reqset_shfd.fdbuf_len,
1801*1137Sarutz 	    PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
1802*1137Sarutz 	if (fbuf == MAP_FAILED) {
1803*1137Sarutz 		ret_val = errno;
18040Sstevel@tonic-gate 		debug(5, "mmap failed. errno=%d\n", errno);
1805*1137Sarutz 		return (ret_val);
18060Sstevel@tonic-gate 	}
18070Sstevel@tonic-gate 	door_dp->dd_buffd = fd;
18080Sstevel@tonic-gate 	door_dp->dd_buf = fbuf;
18090Sstevel@tonic-gate 	door_dp->dd_buf_len = req->reqset_shfd.fdbuf_len;
1810*1137Sarutz 
18110Sstevel@tonic-gate 	return (0);
18120Sstevel@tonic-gate }
18130Sstevel@tonic-gate 
18140Sstevel@tonic-gate static int32_t
18150Sstevel@tonic-gate reassign_block(door_data_t *door_dp, smedia_services_t *req)
18160Sstevel@tonic-gate {
18170Sstevel@tonic-gate 	struct uscsi_cmd	ucmd;
18180Sstevel@tonic-gate 	union scsi_cdb		cdb;
18190Sstevel@tonic-gate 	int32_t			ret_val;
18200Sstevel@tonic-gate 	int32_t			sector_size;
18210Sstevel@tonic-gate 	char			*read_buf;
18220Sstevel@tonic-gate 	uchar_t			mode_data[MD_LEN];
18230Sstevel@tonic-gate 
18240Sstevel@tonic-gate 	if (get_mode_page(door_dp->dd_fd, 0, 1,
1825*1137Sarutz 	    mode_data, MD_LEN) < 0) {
18260Sstevel@tonic-gate 		debug(5, "Mode sense failed\n");
18270Sstevel@tonic-gate 		ret_val =  scsi_reassign_block(door_dp->dd_fd,
1828*1137Sarutz 		    req->reqreassign_block.blockno);
18290Sstevel@tonic-gate 		if (ret_val != 0)
18300Sstevel@tonic-gate 			return (-1);
18310Sstevel@tonic-gate 		return (0);
18320Sstevel@tonic-gate 	}
18330Sstevel@tonic-gate 
18340Sstevel@tonic-gate 	/*
18350Sstevel@tonic-gate 	 * No need to check if enough data is returned for
18360Sstevel@tonic-gate 	 * AWRE bit or not.
18370Sstevel@tonic-gate 	 * It will be 0 otherwise which needs to reassign the block.
18380Sstevel@tonic-gate 	 */
18390Sstevel@tonic-gate 	if (!(mode_data[AWRE_OFFSET] & AWRE)) {
18400Sstevel@tonic-gate 		debug(5, "AWRE bit not set\n");
18410Sstevel@tonic-gate 		ret_val =  scsi_reassign_block(door_dp->dd_fd,
18420Sstevel@tonic-gate 			req->reqreassign_block.blockno);
18430Sstevel@tonic-gate 		if (ret_val != 0)
18440Sstevel@tonic-gate 			return (-1);
18450Sstevel@tonic-gate 		return (0);
18460Sstevel@tonic-gate 	}
18470Sstevel@tonic-gate 	sector_size = (mode_data[BLOCK_LEN_OFFSET] << 16) |
18480Sstevel@tonic-gate 		(mode_data[BLOCK_LEN_OFFSET + 1] << 8) |
18490Sstevel@tonic-gate 		mode_data[BLOCK_LEN_OFFSET + 2];
18500Sstevel@tonic-gate 
18510Sstevel@tonic-gate 	debug(5, "REASSIGN BLOCK: sec size = 0x%x\n", sector_size);
18520Sstevel@tonic-gate 	read_buf = (char *)malloc(sector_size);
18530Sstevel@tonic-gate 	if (read_buf == NULL) {
18540Sstevel@tonic-gate 		/* Alloc failed. Atleast reassign the block */
18550Sstevel@tonic-gate 		ret_val =  scsi_reassign_block(door_dp->dd_fd,
18560Sstevel@tonic-gate 			req->reqreassign_block.blockno);
18570Sstevel@tonic-gate 		if (ret_val != 0)
18580Sstevel@tonic-gate 			return (-1);
18590Sstevel@tonic-gate 		return (0);
18600Sstevel@tonic-gate 	}
18610Sstevel@tonic-gate 
18620Sstevel@tonic-gate 	(void) memset(read_buf, 0, sector_size);
18630Sstevel@tonic-gate 	/* Read the sector */
18640Sstevel@tonic-gate 	debug(5, "Reading the block %d\n",
18650Sstevel@tonic-gate 		(uint32_t)req->reqreassign_block.blockno);
18660Sstevel@tonic-gate 
18670Sstevel@tonic-gate 	(void) memset((void *) &ucmd, 0, sizeof (ucmd));
18680Sstevel@tonic-gate 	(void) memset((void *) &cdb, 0, sizeof (union scsi_cdb));
18690Sstevel@tonic-gate 
18700Sstevel@tonic-gate 	cdb.scc_cmd = SCMD_READ_G1;
18710Sstevel@tonic-gate 	FORMG1ADDR(&cdb, req->reqreassign_block.blockno);
18720Sstevel@tonic-gate 	FORMG1COUNT(&cdb, 1);	/* One block */
18730Sstevel@tonic-gate 
18740Sstevel@tonic-gate 	ucmd.uscsi_cdb = (caddr_t)&cdb;
18750Sstevel@tonic-gate 	ucmd.uscsi_cdblen = CDB_GROUP1;
18760Sstevel@tonic-gate 	ucmd.uscsi_bufaddr = (caddr_t)read_buf;
18770Sstevel@tonic-gate 	ucmd.uscsi_buflen = sector_size;
18780Sstevel@tonic-gate 	ucmd.uscsi_timeout = 120;	/* If 0, HBA hangs forever */
18790Sstevel@tonic-gate 	(void) do_uscsi_cmd(door_dp->dd_fd, &ucmd, USCSI_READ);
18800Sstevel@tonic-gate 
18810Sstevel@tonic-gate 	/* Write the data back */
18820Sstevel@tonic-gate 
18830Sstevel@tonic-gate 	debug(5, "Writing the block %d\n",
18840Sstevel@tonic-gate 		(uint32_t)req->reqreassign_block.blockno);
18850Sstevel@tonic-gate 	(void) memset((void *) &ucmd, 0, sizeof (ucmd));
18860Sstevel@tonic-gate 	(void) memset((void *) &cdb, 0, sizeof (cdb));
18870Sstevel@tonic-gate 
18880Sstevel@tonic-gate 	cdb.scc_cmd = SCMD_WRITE_G1;
18890Sstevel@tonic-gate 	FORMG1ADDR(&cdb, req->reqreassign_block.blockno);
18900Sstevel@tonic-gate 	FORMG1COUNT(&cdb, 1);	/* One block */
18910Sstevel@tonic-gate 
18920Sstevel@tonic-gate 	ucmd.uscsi_cdb = (caddr_t)&cdb;
18930Sstevel@tonic-gate 	ucmd.uscsi_cdblen = CDB_GROUP1;
18940Sstevel@tonic-gate 	ucmd.uscsi_bufaddr = (caddr_t)read_buf;
18950Sstevel@tonic-gate 	ucmd.uscsi_buflen = sector_size;
18960Sstevel@tonic-gate 	ucmd.uscsi_timeout = 120;	/* If 0, HBA hangs forever */
18970Sstevel@tonic-gate 	ret_val = do_uscsi_cmd(door_dp->dd_fd, &ucmd, USCSI_WRITE);
18980Sstevel@tonic-gate 	free(read_buf);
18990Sstevel@tonic-gate 	if (ret_val || ucmd.uscsi_status) {
19000Sstevel@tonic-gate 		debug(5, "Reassign failed: %d - %d errno = %d\n",
19010Sstevel@tonic-gate 			ret_val, ucmd.uscsi_status, errno);
19020Sstevel@tonic-gate 		ret_val = scsi_reassign_block(door_dp->dd_fd,
19030Sstevel@tonic-gate 			req->reqreassign_block.blockno);
19040Sstevel@tonic-gate 		if (ret_val != 0)
19050Sstevel@tonic-gate 			return (-1);
19060Sstevel@tonic-gate 		return (0);
19070Sstevel@tonic-gate 	}
19080Sstevel@tonic-gate 
19090Sstevel@tonic-gate 	return (0);
19100Sstevel@tonic-gate }
19110Sstevel@tonic-gate 
19120Sstevel@tonic-gate static void
19130Sstevel@tonic-gate close_door_descs(door_desc_t *dp, uint_t ndesc)
19140Sstevel@tonic-gate {
19150Sstevel@tonic-gate 	while (ndesc > 0) {
19160Sstevel@tonic-gate 		int fd = dp->d_data.d_desc.d_descriptor;
19170Sstevel@tonic-gate 		if (dp->d_attributes & DOOR_DESCRIPTOR)
19180Sstevel@tonic-gate 			(void) close(fd);
19190Sstevel@tonic-gate 		dp++;
19200Sstevel@tonic-gate 		ndesc--;
19210Sstevel@tonic-gate 	}
19220Sstevel@tonic-gate }
19230Sstevel@tonic-gate 
1924*1137Sarutz /*
1925*1137Sarutz  * This is a Death Door's service procedure.
1926*1137Sarutz  *
1927*1137Sarutz  * This procedure is a NOP because the Death Door functionality
1928*1137Sarutz  * is no longer used and will be removed in the future.
1929*1137Sarutz  */
1930*1137Sarutz /*ARGSUSED*/
19310Sstevel@tonic-gate static void
1932*1137Sarutz death_servproc(void *cookie, char *argp, size_t arg_size,
1933*1137Sarutz     door_desc_t *dp, uint_t ndesc)
1934*1137Sarutz {
1935*1137Sarutz 	debug(1, "death_servproc[%d]: argp = 0x%p  "
1936*1137Sarutz 	    "Death Door[%d]\n", pthread_self(), (void *)argp,
1937*1137Sarutz 	    ((door_data_t *)cookie)->dd_ddoor_descriptor);
1938*1137Sarutz 
1939*1137Sarutz 	(void) door_return(NULL, 0, NULL, 0);
1940*1137Sarutz }
1941*1137Sarutz 
1942*1137Sarutz /*
1943*1137Sarutz  * This is a Client Door's service procedure.
1944*1137Sarutz  *
1945*1137Sarutz  * This procedure is specified in the door_create() of a Client Door,
1946*1137Sarutz  * and its functionality represents the bulk of services that the
1947*1137Sarutz  * rpc.smserverd daemon offers.
1948*1137Sarutz  */
1949*1137Sarutz static void
1950*1137Sarutz client_servproc(void *cookie, char *argp, size_t arg_size,
19510Sstevel@tonic-gate     door_desc_t *dp, uint_t ndesc)
19520Sstevel@tonic-gate {
19530Sstevel@tonic-gate 	smedia_services_t	*req;
19540Sstevel@tonic-gate 	smedia_services_t	rmsvc;
19550Sstevel@tonic-gate 	smedia_reterror_t	reterror;
19560Sstevel@tonic-gate 	smedia_retraw_read_t	retraw_read;
19570Sstevel@tonic-gate 	struct scsi_inquiry	inq;
19580Sstevel@tonic-gate 	struct dk_minfo		media_info;
19590Sstevel@tonic-gate 	struct dk_geom		dkgeom;
19600Sstevel@tonic-gate 	int32_t			status;
19610Sstevel@tonic-gate 	uchar_t			data[18];
19620Sstevel@tonic-gate 	int32_t			completed = 0;
19630Sstevel@tonic-gate 	door_data_t		*door_dp;
19640Sstevel@tonic-gate 	size_t			retbuf_size;
19650Sstevel@tonic-gate 	struct uscsi_cmd	ucmd;
19660Sstevel@tonic-gate 	union scsi_cdb		cdb;
19670Sstevel@tonic-gate 	int32_t			ret_val, err;
19680Sstevel@tonic-gate 	char			rq_data[RQ_LEN];
1969*1137Sarutz 	uint_t			nexpected_desc;
19700Sstevel@tonic-gate 	struct vtoc		vtoc;
19710Sstevel@tonic-gate 
19720Sstevel@tonic-gate 	door_dp = (door_data_t *)cookie;
19730Sstevel@tonic-gate 	req = (smedia_services_t *)((void *)argp);
19740Sstevel@tonic-gate 
1975*1137Sarutz 	debug(10, "client_servproc[%d]...\n", pthread_self());
19760Sstevel@tonic-gate 
19770Sstevel@tonic-gate 	if (argp == DOOR_UNREF_DATA) {
1978*1137Sarutz 		debug(5, "client_servproc[%d]: req = DOOR_UNREF_DATA\n",
1979*1137Sarutz 		    pthread_self());
19800Sstevel@tonic-gate 		debug(5, "Client has exited. Cleaning up resources\n");
1981*1137Sarutz 
19820Sstevel@tonic-gate 		(void) mutex_lock(&svcstate_lock);
19830Sstevel@tonic-gate 		svccount--;
19840Sstevel@tonic-gate 		(void) mutex_unlock(&svcstate_lock);
1985*1137Sarutz 
19860Sstevel@tonic-gate 		cleanup(door_dp);
1987*1137Sarutz 		return;
19880Sstevel@tonic-gate 	}
1989*1137Sarutz 
19900Sstevel@tonic-gate 	(void) mutex_lock(&svcstate_lock);
19910Sstevel@tonic-gate 	svcstate = _SERVED;
19920Sstevel@tonic-gate 	(void) mutex_unlock(&svcstate_lock);
19930Sstevel@tonic-gate 
19940Sstevel@tonic-gate 	rmsvc.in.cnum = req->in.cnum;
1995*1137Sarutz 	debug(5, "client_servproc[%d]: req = %s\n", pthread_self(),
1996*1137Sarutz 	    xlate_cnum(req->in.cnum));
19970Sstevel@tonic-gate 
19980Sstevel@tonic-gate 	/*
19990Sstevel@tonic-gate 	 * Our caller may have passed more descriptors than we expected.
20000Sstevel@tonic-gate 	 * If so, we silently close (and ignore) them.
20010Sstevel@tonic-gate 	 */
2002*1137Sarutz 	nexpected_desc = (req->in.cnum == SMEDIA_CNUM_SET_SHFD) ? 1 : 0;
2003*1137Sarutz 	if (ndesc > nexpected_desc) {
2004*1137Sarutz 		close_door_descs(dp + nexpected_desc, ndesc - nexpected_desc);
2005*1137Sarutz 	}
20060Sstevel@tonic-gate 
20070Sstevel@tonic-gate 	switch (req->in.cnum) {
20080Sstevel@tonic-gate 	default:
2009*1137Sarutz 		debug(5, "client_servproc: unknown command %d\n", req->in.cnum);
20100Sstevel@tonic-gate 		door_ret_err(&reterror, ENOTSUP);
20110Sstevel@tonic-gate 		break;
20120Sstevel@tonic-gate 
2013*1137Sarutz 	case SMEDIA_CNUM_SET_SHFD:
20140Sstevel@tonic-gate 		if (ndesc == 0)
20150Sstevel@tonic-gate 			door_ret_err(&reterror, EINVAL);
20160Sstevel@tonic-gate 		/*
2017*1137Sarutz 		 * Allocate shared memory for this connection.
2018*1137Sarutz 		 * If this connection already has shared memory,
2019*1137Sarutz 		 * deallocate before doing the allocation.
20200Sstevel@tonic-gate 		 */
2021*1137Sarutz 		ret_val = set_shfd(door_dp, dp->d_data.d_desc.d_descriptor,
2022*1137Sarutz 		    req);
20230Sstevel@tonic-gate 		if (ret_val == 0) {
20240Sstevel@tonic-gate 			reterror.cnum = SMEDIA_CNUM_SET_SHFD;
20250Sstevel@tonic-gate 			reterror.errnum = 0;
2026*1137Sarutz 
20270Sstevel@tonic-gate 			my_door_return((char *)&reterror,
20280Sstevel@tonic-gate 				sizeof (smedia_reterror_t), 0, 0);
20290Sstevel@tonic-gate 		} else {
20300Sstevel@tonic-gate 			(void) close(dp->d_data.d_desc.d_descriptor);
2031*1137Sarutz 			door_ret_err(&reterror, ret_val);
20320Sstevel@tonic-gate 		}
20330Sstevel@tonic-gate 		break;
20340Sstevel@tonic-gate 
2035*1137Sarutz 	case SMEDIA_CNUM_RAW_READ:
20360Sstevel@tonic-gate 		debug(10, " arg size = %d blk num=0x%x nbytes = 0x%x \n",
20370Sstevel@tonic-gate 			(int)arg_size,
20380Sstevel@tonic-gate 			(uint32_t)req->reqraw_read.blockno,
20390Sstevel@tonic-gate 			req->reqraw_read.nbytes);
20400Sstevel@tonic-gate 		retbuf_size = sizeof (smedia_retraw_read_t);
20410Sstevel@tonic-gate 		if (req->reqraw_read.nbytes == 0) {
20420Sstevel@tonic-gate 			/* Nothing to write */
20430Sstevel@tonic-gate 			rmsvc.retraw_write.nbytes = 0;
20440Sstevel@tonic-gate 			my_door_return((char *)&rmsvc,
20450Sstevel@tonic-gate 				sizeof (smedia_retraw_write_t), 0, 0);
20460Sstevel@tonic-gate 		}
20470Sstevel@tonic-gate 		retraw_read.cnum = SMEDIA_CNUM_RAW_READ;
20480Sstevel@tonic-gate 		ret_val = raw_read(door_dp, req);
20490Sstevel@tonic-gate 		if (ret_val == -1) {
20500Sstevel@tonic-gate 			door_ret_err(&reterror, errno);
20510Sstevel@tonic-gate 		}
20520Sstevel@tonic-gate 		retraw_read.nbytes = ret_val;
20530Sstevel@tonic-gate 		my_door_return((char *)&retraw_read, retbuf_size, 0, 0);
20540Sstevel@tonic-gate 		break;
20550Sstevel@tonic-gate 
20560Sstevel@tonic-gate 	case	SMEDIA_CNUM_USCSI_CMD:
20570Sstevel@tonic-gate 		retbuf_size = sizeof (smedia_retuscsi_cmd_t);
20580Sstevel@tonic-gate 		rmsvc.retuscsi_cmd.cnum = SMEDIA_CNUM_USCSI_CMD;
20590Sstevel@tonic-gate 		ucmd.uscsi_flags = req->requscsi_cmd.uscsi_flags;
20600Sstevel@tonic-gate 		ucmd.uscsi_cdb = (caddr_t)&req->requscsi_cmd.uscsi_cdb;
20610Sstevel@tonic-gate 		ucmd.uscsi_cdblen = req->requscsi_cmd.uscsi_cdblen;
20620Sstevel@tonic-gate 		ucmd.uscsi_bufaddr = (caddr_t)door_dp->dd_buf;
20630Sstevel@tonic-gate 		ucmd.uscsi_buflen = req->requscsi_cmd.uscsi_buflen;
20640Sstevel@tonic-gate 		ucmd.uscsi_timeout = req->requscsi_cmd.uscsi_timeout;
20650Sstevel@tonic-gate 		ucmd.uscsi_rqlen = req->requscsi_cmd.uscsi_rqlen;
20660Sstevel@tonic-gate 		ucmd.uscsi_rqbuf = (caddr_t)&rmsvc.retuscsi_cmd.uscsi_rqbuf;
2067*1137Sarutz 		debug(5, "USCSI CMD 0x%x requested.\n",
20680Sstevel@tonic-gate 		    req->requscsi_cmd.uscsi_cdb[0]);
20690Sstevel@tonic-gate 		/*
20700Sstevel@tonic-gate 		 * Check the device type and invalid flags specified.
20710Sstevel@tonic-gate 		 * We permit operations only on CDROM devices types.
20720Sstevel@tonic-gate 		 */
2073*1137Sarutz 		errno = invalid_uscsi_operation(door_dp, &ucmd);
20740Sstevel@tonic-gate 		if (errno) {
20750Sstevel@tonic-gate 			door_ret_err(&reterror, errno);
20760Sstevel@tonic-gate 		}
20770Sstevel@tonic-gate 
20780Sstevel@tonic-gate 		if ((req->requscsi_cmd.uscsi_buflen) &&
20790Sstevel@tonic-gate 		    ((req->requscsi_cmd.uscsi_buflen > door_dp->dd_buf_len) ||
20800Sstevel@tonic-gate 		    (door_dp->dd_buf == NULL))) {
2081*1137Sarutz 			debug(5, "uscsi_cmd failed: uscsi_buflen=0x%x "
2082*1137Sarutz 			    "dd_buf_len=0x%x dd_buf=0x%p\n",
2083*1137Sarutz 			    req->requscsi_cmd.uscsi_buflen,
2084*1137Sarutz 			    door_dp->dd_buf_len,
2085*1137Sarutz 			    door_dp->dd_buf);
20860Sstevel@tonic-gate 			errno = EINVAL;
20870Sstevel@tonic-gate 			door_ret_err(&reterror, errno);
20880Sstevel@tonic-gate 		}
20890Sstevel@tonic-gate 		ret_val = do_uscsi_cmd(door_dp->dd_fd,
20900Sstevel@tonic-gate 			&ucmd, req->requscsi_cmd.uscsi_flags);
20910Sstevel@tonic-gate 		rmsvc.retuscsi_cmd.uscsi_status = ucmd.uscsi_status;
20920Sstevel@tonic-gate 		rmsvc.retuscsi_cmd.uscsi_resid = ucmd.uscsi_resid;
20930Sstevel@tonic-gate 		rmsvc.retuscsi_cmd.uscsi_rqstatus = ucmd.uscsi_rqstatus;
20940Sstevel@tonic-gate 		rmsvc.retuscsi_cmd.uscsi_rqresid = ucmd.uscsi_rqresid;
20950Sstevel@tonic-gate 		rmsvc.retuscsi_cmd.uscsi_retval = ret_val;
20960Sstevel@tonic-gate 		rmsvc.retuscsi_cmd.uscsi_errno = errno;
20970Sstevel@tonic-gate 		if (ret_val || ucmd.uscsi_status) {
20980Sstevel@tonic-gate 			debug(5, "uscsi_cmd failed: %d - %d errno = %d\n",
20990Sstevel@tonic-gate 				ret_val, ucmd.uscsi_status, errno);
21000Sstevel@tonic-gate 		}
21010Sstevel@tonic-gate 		my_door_return((char *)&rmsvc, retbuf_size, 0, 0);
21020Sstevel@tonic-gate 		break;
21030Sstevel@tonic-gate 
21040Sstevel@tonic-gate 	case SMEDIA_CNUM_RAW_WRITE:
21050Sstevel@tonic-gate 		if (req->reqraw_write.nbytes == 0) {
21060Sstevel@tonic-gate 			/* Nothing to write */
21070Sstevel@tonic-gate 			rmsvc.retraw_write.nbytes = 0;
21080Sstevel@tonic-gate 			my_door_return((char *)&rmsvc,
21090Sstevel@tonic-gate 				sizeof (smedia_retraw_write_t), 0, 0);
21100Sstevel@tonic-gate 		}
21110Sstevel@tonic-gate 		ret_val = raw_write(door_dp, req);
21120Sstevel@tonic-gate 		if (ret_val == -1)
21130Sstevel@tonic-gate 			door_ret_err(&reterror, errno);
21140Sstevel@tonic-gate 		rmsvc.retraw_write.nbytes = ret_val;
21150Sstevel@tonic-gate 		my_door_return((char *)&rmsvc, sizeof (smedia_retraw_write_t),
21160Sstevel@tonic-gate 			0, 0);
21170Sstevel@tonic-gate 		break;
21180Sstevel@tonic-gate 
21190Sstevel@tonic-gate 	case SMEDIA_CNUM_GET_DEVICE_INFO:
21200Sstevel@tonic-gate 
21210Sstevel@tonic-gate 		(void) memset((void *) &inq, 0, sizeof (inq));
21220Sstevel@tonic-gate 		(void) memset((void *) &ucmd, 0, sizeof (ucmd));
21230Sstevel@tonic-gate 		(void) memset((void *) &cdb, 0, sizeof (union scsi_cdb));
21240Sstevel@tonic-gate 		cdb.scc_cmd = SCMD_INQUIRY;
21250Sstevel@tonic-gate 		FORMG0COUNT(&cdb, sizeof (inq));
21260Sstevel@tonic-gate 		ucmd.uscsi_cdb = (caddr_t)&cdb;
21270Sstevel@tonic-gate 		ucmd.uscsi_cdblen = CDB_GROUP0;
21280Sstevel@tonic-gate 		ucmd.uscsi_bufaddr = (caddr_t)&inq;
21290Sstevel@tonic-gate 		ucmd.uscsi_buflen = sizeof (inq);
21300Sstevel@tonic-gate 		ucmd.uscsi_timeout = 120;	/* If 0, HBA hangs forever */
21310Sstevel@tonic-gate 		ucmd.uscsi_rqlen = RQ_LEN;
21320Sstevel@tonic-gate 		ucmd.uscsi_rqbuf = rq_data;
21330Sstevel@tonic-gate 		ret_val = do_uscsi_cmd(door_dp->dd_fd,
21340Sstevel@tonic-gate 			&ucmd, USCSI_READ|USCSI_RQENABLE);
21350Sstevel@tonic-gate 		if (ret_val || ucmd.uscsi_status) {
21360Sstevel@tonic-gate 			debug(5, "inquiry failed: %d - %d errno = %d\n",
21370Sstevel@tonic-gate 				ret_val, ucmd.uscsi_status, errno);
21380Sstevel@tonic-gate 			door_ret_err(&reterror, errno);
21390Sstevel@tonic-gate 		}
21400Sstevel@tonic-gate 
21410Sstevel@tonic-gate 		debug(5, "%s\n", inq.inq_vid);
21420Sstevel@tonic-gate 		debug(5, "%s\n", rmsvc.retget_device_info.sm_vendor_name);
21430Sstevel@tonic-gate 
21440Sstevel@tonic-gate 		(void) strlcpy(rmsvc.retget_device_info.sm_vendor_name,
21450Sstevel@tonic-gate 			inq.inq_vid, 8);
21460Sstevel@tonic-gate 		rmsvc.retget_device_info.sm_vendor_name[8] = 0;
21470Sstevel@tonic-gate 		(void) strlcpy(rmsvc.retget_device_info.sm_product_name,
21480Sstevel@tonic-gate 			inq.inq_pid, 16);
21490Sstevel@tonic-gate 		rmsvc.retget_device_info.sm_product_name[16] = 0;
21500Sstevel@tonic-gate 		(void) strlcpy(rmsvc.retget_device_info.sm_firmware_version,
21510Sstevel@tonic-gate 			inq.inq_revision, 4);
21520Sstevel@tonic-gate 		rmsvc.retget_device_info.sm_firmware_version[4] = ' ';
21530Sstevel@tonic-gate 		(void) strlcpy(
21540Sstevel@tonic-gate 			&rmsvc.retget_device_info.sm_firmware_version[5],
21550Sstevel@tonic-gate 				inq.inq_serial, 12);
21560Sstevel@tonic-gate 		rmsvc.retget_device_info.sm_product_name[17] = 0;
21570Sstevel@tonic-gate 
21580Sstevel@tonic-gate 		rmsvc.retget_device_info.sm_interface_type = IF_SCSI;
21590Sstevel@tonic-gate 
2160*1137Sarutz 		debug(5, "Vendor name = %s\n",
2161*1137Sarutz 		    rmsvc.retget_device_info.sm_vendor_name);
2162*1137Sarutz 		debug(5, "product name = %s\n",
2163*1137Sarutz 		    rmsvc.retget_device_info.sm_product_name);
2164*1137Sarutz 		debug(5, "Firmware revision = %s\n",
2165*1137Sarutz 		    rmsvc.retget_device_info.sm_firmware_version);
2166*1137Sarutz 
21670Sstevel@tonic-gate 		my_door_return((char *)&rmsvc.retget_device_info,
21680Sstevel@tonic-gate 			sizeof (smedia_retget_device_info_t), 0, 0);
21690Sstevel@tonic-gate 		break;
21700Sstevel@tonic-gate 
21710Sstevel@tonic-gate 	case	SMEDIA_CNUM_GET_MEDIUM_PROPERTY:
21720Sstevel@tonic-gate 
21730Sstevel@tonic-gate 		(void) memset((void *)&rmsvc.retget_medium_property.smprop,
21740Sstevel@tonic-gate 			0, sizeof (smmedium_prop_t));
21750Sstevel@tonic-gate 
21760Sstevel@tonic-gate 		ret_val = ioctl(door_dp->dd_fd, DKIOCGMEDIAINFO, &media_info);
21770Sstevel@tonic-gate 
21780Sstevel@tonic-gate 		if (ret_val < 0) {
21790Sstevel@tonic-gate 			uint32_t capacity;
21800Sstevel@tonic-gate 			uint32_t blocksize;
21810Sstevel@tonic-gate 			/*
21820Sstevel@tonic-gate 			 * Devices may fail DKIOCGMEDIAINFO if an unformed
21830Sstevel@tonic-gate 			 * media is inserted. We can get the capacity
21840Sstevel@tonic-gate 			 * information from the SCMD_READ_FORMAT_CAP command.
21850Sstevel@tonic-gate 			 */
21860Sstevel@tonic-gate 
2187*1137Sarutz 			debug(5, "DKIOCGMEDIAINFO failed; using "
2188*1137Sarutz 			    "SCMD_READ_FORMAT_CAP");
21890Sstevel@tonic-gate 			ret_val = get_media_capacity(door_dp->dd_fd,
21900Sstevel@tonic-gate 			    &capacity, &blocksize);
21910Sstevel@tonic-gate 
21920Sstevel@tonic-gate 			if (ret_val >= 0) {
21930Sstevel@tonic-gate 				media_info.dki_lbsize =	blocksize;
21940Sstevel@tonic-gate 				media_info.dki_capacity = capacity;
21950Sstevel@tonic-gate 			} else {
21960Sstevel@tonic-gate 				debug(5, "SCMD_READ_FORMAT_CAP failed");
21970Sstevel@tonic-gate 				door_ret_err(&reterror, errno);
21980Sstevel@tonic-gate 			}
21990Sstevel@tonic-gate 		}
22000Sstevel@tonic-gate 		rmsvc.retget_medium_property.smprop.sm_blocksize =
22010Sstevel@tonic-gate 		    media_info.dki_lbsize;
22020Sstevel@tonic-gate 		rmsvc.retget_medium_property.smprop.sm_capacity =
22030Sstevel@tonic-gate 		    media_info.dki_capacity;
22040Sstevel@tonic-gate 
22050Sstevel@tonic-gate 		rmsvc.retget_medium_property.smprop.sm_media_type =
22060Sstevel@tonic-gate 		    media_info.dki_media_type;
22070Sstevel@tonic-gate 		/*
22080Sstevel@tonic-gate 		 * These devices show as SCSI devices but we need to treat it
22090Sstevel@tonic-gate 		 * differently. so we need a seperate class.
22100Sstevel@tonic-gate 		 */
22110Sstevel@tonic-gate 		if (get_device_type_scsi(door_dp->dd_fd, &inq) == SCSI_FLOPPY) {
22120Sstevel@tonic-gate 			rmsvc.retget_medium_property.smprop.sm_media_type =
22130Sstevel@tonic-gate 			    SM_SCSI_FLOPPY;
22140Sstevel@tonic-gate 		}
22150Sstevel@tonic-gate 
22160Sstevel@tonic-gate 		/* Check for EFI type because DKIOCGGEOM does not support EFI */
22170Sstevel@tonic-gate 		ret_val = ioctl(door_dp->dd_fd, DKIOCGVTOC, &vtoc);
22180Sstevel@tonic-gate 		if (!((ret_val < 0) && (errno == ENOTSUP))) {
22190Sstevel@tonic-gate 			ret_val = ioctl(door_dp->dd_fd, DKIOCGGEOM, &dkgeom);
22200Sstevel@tonic-gate 			if (ret_val < 0)  {
22210Sstevel@tonic-gate 				/*
22220Sstevel@tonic-gate 				 * DKIOCGGEOM may fail for unformed floppies.
22230Sstevel@tonic-gate 				 * We need to generate the appropriate geometry
22240Sstevel@tonic-gate 				 * information.
22250Sstevel@tonic-gate 				 */
22260Sstevel@tonic-gate 				if (rmsvc.retget_medium_property.smprop.
22270Sstevel@tonic-gate 				    sm_media_type == SM_SCSI_FLOPPY) {
22280Sstevel@tonic-gate 					ret_val = get_floppy_geom(
22290Sstevel@tonic-gate 					    door_dp->dd_fd,
22300Sstevel@tonic-gate 					    media_info.dki_capacity, &dkgeom);
22310Sstevel@tonic-gate 
22320Sstevel@tonic-gate 					if (ret_val < 0) {
22330Sstevel@tonic-gate 						debug(5, "Cannot determine "
22340Sstevel@tonic-gate 						    "media size");
22350Sstevel@tonic-gate 						door_ret_err(&reterror, errno);
22360Sstevel@tonic-gate 					}
22370Sstevel@tonic-gate 				} else {
22380Sstevel@tonic-gate #ifdef sparc
22390Sstevel@tonic-gate 					debug(5, "DKIOCGGEOM ioctl failed");
22400Sstevel@tonic-gate 					door_ret_err(&reterror, errno);
22410Sstevel@tonic-gate #else /* !sparc */
22420Sstevel@tonic-gate 					/*
22430Sstevel@tonic-gate 					 * Try getting Physical geometry on x86.
22440Sstevel@tonic-gate 					 */
22450Sstevel@tonic-gate 					ret_val = ioctl(door_dp->dd_fd,
22460Sstevel@tonic-gate 					    DKIOCG_PHYGEOM, &dkgeom);
22470Sstevel@tonic-gate 					if (ret_val < 0) {
22480Sstevel@tonic-gate 						debug(5, "DKIOCG_PHYGEOM "
22490Sstevel@tonic-gate 						    "ioctl failed");
22500Sstevel@tonic-gate 						door_ret_err(&reterror, errno);
22510Sstevel@tonic-gate 					}
22520Sstevel@tonic-gate #endif /* sparc */
22530Sstevel@tonic-gate 				}
22540Sstevel@tonic-gate 			}
22550Sstevel@tonic-gate 
22560Sstevel@tonic-gate 
22570Sstevel@tonic-gate 			/*
22580Sstevel@tonic-gate 			 * Some faked geometry may not have pcyl filled in so
22590Sstevel@tonic-gate 			 * later calculations using this field will be
22600Sstevel@tonic-gate 			 * incorrect.  We will substitute it with the number of
22610Sstevel@tonic-gate 			 * available cylinders.
22620Sstevel@tonic-gate 			 */
22630Sstevel@tonic-gate 			if (dkgeom.dkg_pcyl == 0)
22640Sstevel@tonic-gate 				rmsvc.retget_medium_property.smprop.sm_pcyl =
22650Sstevel@tonic-gate 				    dkgeom.dkg_ncyl;
22660Sstevel@tonic-gate 			else
22670Sstevel@tonic-gate 				rmsvc.retget_medium_property.smprop.sm_pcyl =
22680Sstevel@tonic-gate 				    dkgeom.dkg_pcyl;
22690Sstevel@tonic-gate 
22700Sstevel@tonic-gate 			rmsvc.retget_medium_property.smprop.sm_nhead =
22710Sstevel@tonic-gate 			    dkgeom.dkg_nhead;
22720Sstevel@tonic-gate 			rmsvc.retget_medium_property.smprop.sm_nsect =
22730Sstevel@tonic-gate 			    dkgeom.dkg_nsect;
22740Sstevel@tonic-gate 		}
22750Sstevel@tonic-gate 
22760Sstevel@tonic-gate 		debug(1, "properties are: lbasize = %d, cap = %llu",
22770Sstevel@tonic-gate 		    media_info.dki_lbsize, media_info.dki_capacity);
22780Sstevel@tonic-gate 
22790Sstevel@tonic-gate 		my_door_return((char *)&rmsvc.retget_medium_property,
22800Sstevel@tonic-gate 			sizeof (smedia_retget_medium_property_t), 0, 0);
22810Sstevel@tonic-gate 		break;
22820Sstevel@tonic-gate 
22830Sstevel@tonic-gate 	case	SMEDIA_CNUM_GET_PROTECTION_STATUS:
22840Sstevel@tonic-gate 		switch (get_device_type_scsi(door_dp->dd_fd, &inq)) {
22850Sstevel@tonic-gate 		case SCSI_FLOPPY:
22860Sstevel@tonic-gate 			status = scsi_floppy_media_status(door_dp->dd_fd);
22870Sstevel@tonic-gate 			break;
22880Sstevel@tonic-gate 		case SCSI_IOMEGA:
22890Sstevel@tonic-gate 			status = scsi_zip_media_status(door_dp->dd_fd);
22900Sstevel@tonic-gate 			break;
22910Sstevel@tonic-gate 		case SCSI_GENERIC:
22920Sstevel@tonic-gate 			status = scsi_media_status(door_dp->dd_fd);
22930Sstevel@tonic-gate 			break;
22940Sstevel@tonic-gate 		default:
22950Sstevel@tonic-gate 			door_ret_err(&reterror, errno);
22960Sstevel@tonic-gate 		}
22970Sstevel@tonic-gate 		if (status < 0)
22980Sstevel@tonic-gate 			door_ret_err(&reterror, errno);
22990Sstevel@tonic-gate 
23000Sstevel@tonic-gate 		rmsvc.retget_protection_status.prot_state.sm_new_state  =
23010Sstevel@tonic-gate 			status;
23020Sstevel@tonic-gate 
23030Sstevel@tonic-gate 		my_door_return((char *)&rmsvc.retget_protection_status,
23040Sstevel@tonic-gate 			sizeof (smedia_retget_protection_status_t), 0, 0);
23050Sstevel@tonic-gate 		break;
23060Sstevel@tonic-gate 
23070Sstevel@tonic-gate 	case	SMEDIA_CNUM_SET_PROTECTION_STATUS:
23080Sstevel@tonic-gate 
23090Sstevel@tonic-gate 		ret_val = set_protection_status(door_dp, req);
23100Sstevel@tonic-gate 		if (ret_val == -1)
23110Sstevel@tonic-gate 			door_ret_err(&reterror, errno);
23120Sstevel@tonic-gate 		else
23130Sstevel@tonic-gate 			my_door_return((char *)&rmsvc.retset_protection_status,
23140Sstevel@tonic-gate 				sizeof (smedia_retset_protection_status_t),
23150Sstevel@tonic-gate 				0, 0);
23160Sstevel@tonic-gate 		break;
23170Sstevel@tonic-gate 
23180Sstevel@tonic-gate 	case SMEDIA_CNUM_FORMAT:
23190Sstevel@tonic-gate 		switch (get_device_type_scsi(door_dp->dd_fd, &inq)) {
23200Sstevel@tonic-gate 		case SCSI_FLOPPY:
23210Sstevel@tonic-gate 			info("formatting floppy");
23220Sstevel@tonic-gate 			err = scsi_floppy_format(door_dp->dd_fd,
23230Sstevel@tonic-gate 				req->reqformat.flavor, req->reqformat.mode);
23240Sstevel@tonic-gate 
23250Sstevel@tonic-gate 			break;
23260Sstevel@tonic-gate 		case SCSI_IOMEGA:
23270Sstevel@tonic-gate 			err = scsi_zip_format(door_dp->dd_fd,
23280Sstevel@tonic-gate 				req->reqformat.flavor, req->reqformat.mode);
23290Sstevel@tonic-gate 			break;
23300Sstevel@tonic-gate 		case SCSI_GENERIC:
23310Sstevel@tonic-gate 			err = scsi_format(door_dp->dd_fd,
23320Sstevel@tonic-gate 				req->reqformat.flavor, req->reqformat.mode);
23330Sstevel@tonic-gate 			break;
23340Sstevel@tonic-gate 		default:
23350Sstevel@tonic-gate 			door_ret_err(&reterror, ENOTSUP);
23360Sstevel@tonic-gate 		}
23370Sstevel@tonic-gate 
23380Sstevel@tonic-gate 		if (err)
23390Sstevel@tonic-gate 			door_ret_err(&reterror, errno);
23400Sstevel@tonic-gate 		my_door_return((char *)&rmsvc.retformat,
23410Sstevel@tonic-gate 			sizeof (smedia_retformat_t), 0, 0);
23420Sstevel@tonic-gate 
23430Sstevel@tonic-gate 		break;
23440Sstevel@tonic-gate 
23450Sstevel@tonic-gate 	case SMEDIA_CNUM_CHECK_FORMAT_STATUS:
23460Sstevel@tonic-gate 
23470Sstevel@tonic-gate 		(void) memset((void *) &cdb, 0, sizeof (union scsi_cdb));
23480Sstevel@tonic-gate 		(void) memset((void *) &ucmd, 0, sizeof (ucmd));
23490Sstevel@tonic-gate 		(void) memset((void *) &data, 0, sizeof (data));
23500Sstevel@tonic-gate 		cdb.scc_cmd = SCMD_REQUEST_SENSE;
23510Sstevel@tonic-gate 		cdb.g0_count0 = sizeof (data);
23520Sstevel@tonic-gate 		ucmd.uscsi_cdb = (caddr_t)&cdb;
23530Sstevel@tonic-gate 		ucmd.uscsi_cdblen = CDB_GROUP0;
23540Sstevel@tonic-gate 		ucmd.uscsi_bufaddr = (caddr_t)&data;
23550Sstevel@tonic-gate 		ucmd.uscsi_buflen = sizeof (data);
23560Sstevel@tonic-gate 		ucmd.uscsi_timeout = 120;	/* If 0, HBA hangs forever */
23570Sstevel@tonic-gate 		ucmd.uscsi_rqlen = RQ_LEN;
23580Sstevel@tonic-gate 		ucmd.uscsi_rqbuf = rq_data;
23590Sstevel@tonic-gate 		ret_val = do_uscsi_cmd(door_dp->dd_fd,
23600Sstevel@tonic-gate 			&ucmd, USCSI_READ|USCSI_RQENABLE);
23610Sstevel@tonic-gate 		if (ret_val || ucmd.uscsi_status) {
23620Sstevel@tonic-gate 			debug(5, "Request sense failed: %d - %d errno = %d\n",
23630Sstevel@tonic-gate 				ret_val, ucmd.uscsi_status, errno);
23640Sstevel@tonic-gate 			door_ret_err(&reterror, errno);
23650Sstevel@tonic-gate 		}
23660Sstevel@tonic-gate 
23670Sstevel@tonic-gate 		if ((data[0] & 0x7F) == DEFERRED_ERROR) {
23680Sstevel@tonic-gate 		/* Deffered error. The format must have failed */
23690Sstevel@tonic-gate 			debug(5, "format failed!\n");
23700Sstevel@tonic-gate 			door_ret_err(&reterror, EIO);
23710Sstevel@tonic-gate 		}
23720Sstevel@tonic-gate 
23730Sstevel@tonic-gate 		if (data[SKSV_OFFSET] & SKSV_FIELD) {
23740Sstevel@tonic-gate 			completed =
23750Sstevel@tonic-gate 				(data[FORMAT_PROGRESS_INDICATOR_OFFSET_0] << 8)
23760Sstevel@tonic-gate 				| data[FORMAT_PROGRESS_INDICATOR_OFFSET_1];
23770Sstevel@tonic-gate 			completed = (completed*100/65536);
23780Sstevel@tonic-gate 		} else {
23790Sstevel@tonic-gate 			completed = (100);
23800Sstevel@tonic-gate 		}
23810Sstevel@tonic-gate 		rmsvc.retcheck_format_status.percent_complete = completed;
23820Sstevel@tonic-gate 		my_door_return((char *)&rmsvc.retcheck_format_status,
23830Sstevel@tonic-gate 			sizeof (smedia_retcheck_format_status_t), 0, 0);
23840Sstevel@tonic-gate 		break;
23850Sstevel@tonic-gate 
23860Sstevel@tonic-gate 	case SMEDIA_CNUM_REASSIGN_BLOCK:
23870Sstevel@tonic-gate 
23880Sstevel@tonic-gate 		ret_val = reassign_block(door_dp, req);
23890Sstevel@tonic-gate 		if (ret_val == -1)
23900Sstevel@tonic-gate 			door_ret_err(&reterror, errno);
23910Sstevel@tonic-gate 		my_door_return((char *)&rmsvc.retreassign_block,
23920Sstevel@tonic-gate 			sizeof (smedia_retreassign_block_t), 0, 0);
23930Sstevel@tonic-gate 		break;
23940Sstevel@tonic-gate 
23950Sstevel@tonic-gate 	}	/* end of switch */
23960Sstevel@tonic-gate 
23970Sstevel@tonic-gate 	debug(10, "Exiting client server...\n");
23980Sstevel@tonic-gate 	my_door_return((char *)&reterror, sizeof (smedia_reterror_t), 0, 0);
23990Sstevel@tonic-gate }
24000Sstevel@tonic-gate 
2401*1137Sarutz /*
2402*1137Sarutz  * This is the service procedure for the door that is associated with
2403*1137Sarutz  * the (doorfs) filesystem Door that is created at 'smedia_service'.
2404*1137Sarutz  */
24050Sstevel@tonic-gate /*ARGSUSED*/
24060Sstevel@tonic-gate static void
2407*1137Sarutz main_servproc(void *server_data, char *argp, size_t arg_size,
24080Sstevel@tonic-gate     door_desc_t *dp, uint_t ndesc)
24090Sstevel@tonic-gate {
24100Sstevel@tonic-gate 	smedia_services_t	*req;
24110Sstevel@tonic-gate 	door_cred_t	door_credentials;
24120Sstevel@tonic-gate 	int		ret_val;
24130Sstevel@tonic-gate 	door_data_t	*ddata;
24140Sstevel@tonic-gate 	smedia_reterror_t	reterror;
24150Sstevel@tonic-gate 	smedia_reterror_t	retok;
24160Sstevel@tonic-gate 	struct	stat	stat;
24170Sstevel@tonic-gate 	door_desc_t	*didpp;
24180Sstevel@tonic-gate 	struct dk_cinfo dkinfo;
2419*1137Sarutz 	uint_t		nexpected_desc;
2420*1137Sarutz 
2421*1137Sarutz 	debug(10, "Entering main_servproc[%d].\n", pthread_self());
24220Sstevel@tonic-gate 
24230Sstevel@tonic-gate 	didpp = dp;
24240Sstevel@tonic-gate 	(void) mutex_lock(&svcstate_lock);
24250Sstevel@tonic-gate 	svcstate = _SERVED;
24260Sstevel@tonic-gate 	(void) mutex_unlock(&svcstate_lock);
24270Sstevel@tonic-gate 
24280Sstevel@tonic-gate 	reterror.cnum = SMEDIA_CNUM_ERROR;
24290Sstevel@tonic-gate 	reterror.errnum = SMEDIA_FAILURE;
2430*1137Sarutz 
24310Sstevel@tonic-gate 	if (argp == NULL) {
24320Sstevel@tonic-gate 		debug(5, "argp is NULL\n");
24330Sstevel@tonic-gate 		if (ndesc > 0)
24340Sstevel@tonic-gate 			close_door_descs(dp, ndesc);
24350Sstevel@tonic-gate 		my_door_return((char *)&reterror,
24360Sstevel@tonic-gate 		    sizeof (smedia_reterror_t), 0, 0);
24370Sstevel@tonic-gate 	}
24380Sstevel@tonic-gate 
24390Sstevel@tonic-gate 	req = (smedia_services_t *)((void *)argp);
2440*1137Sarutz 
24410Sstevel@tonic-gate 	retok.cnum = req->in.cnum;
24420Sstevel@tonic-gate 	retok.errnum = 0;
24430Sstevel@tonic-gate 
24440Sstevel@tonic-gate 	debug(5, "req = %s arg_size = 0x%x \n",
2445*1137Sarutz 	    xlate_cnum(req->reqopen.cnum), arg_size);
24460Sstevel@tonic-gate 
24470Sstevel@tonic-gate 	/*
24480Sstevel@tonic-gate 	 * Our caller may have passed more descriptors than we expected.
24490Sstevel@tonic-gate 	 * If so, we silently close (and ignore) them.
24500Sstevel@tonic-gate 	 */
2451*1137Sarutz 	nexpected_desc = (req->in.cnum == SMEDIA_CNUM_OPEN_FD) ? 1 : 0;
2452*1137Sarutz 	if (ndesc > nexpected_desc) {
2453*1137Sarutz 		close_door_descs(dp + nexpected_desc, ndesc - nexpected_desc);
2454*1137Sarutz 	}
24550Sstevel@tonic-gate 
24560Sstevel@tonic-gate 	switch (req->in.cnum) {
24570Sstevel@tonic-gate 	default:
2458*1137Sarutz 		debug(5, "main_servproc: unknown command 0x%x\n",
2459*1137Sarutz 		    req->reqopen.cnum);
24600Sstevel@tonic-gate 		break;
24610Sstevel@tonic-gate 
2462*1137Sarutz 	case SMEDIA_CNUM_PING:
24630Sstevel@tonic-gate 		/*
24640Sstevel@tonic-gate 		 * This service is to indicate that server is up and
24650Sstevel@tonic-gate 		 * running. It is usually called from another instance of
24660Sstevel@tonic-gate 		 * server that is started.
24670Sstevel@tonic-gate 		 */
24680Sstevel@tonic-gate 		reterror.cnum = SMEDIA_CNUM_PING;
24690Sstevel@tonic-gate 		reterror.errnum = 0;
24700Sstevel@tonic-gate 		my_door_return((char *)&reterror,
2471*1137Sarutz 		    sizeof (smedia_reterror_t), 0, 0);
24720Sstevel@tonic-gate 		break;
24730Sstevel@tonic-gate 
24740Sstevel@tonic-gate 
2475*1137Sarutz 	case SMEDIA_CNUM_OPEN_FD:
24760Sstevel@tonic-gate 
24770Sstevel@tonic-gate 		debug(5, "ndesc = %d\n", ndesc);
24780Sstevel@tonic-gate 		if (ndesc == 0) {
24790Sstevel@tonic-gate 			my_door_return((char *)&reterror,
2480*1137Sarutz 			    sizeof (smedia_reterror_t), 0, 0);
24810Sstevel@tonic-gate 		}
2482*1137Sarutz 		debug(5, "Checking file descriptor of target device\n");
24830Sstevel@tonic-gate 		if (fstat(didpp->d_data.d_desc.d_descriptor, &stat) < 0) {
2484*1137Sarutz 			warning(gettext("main_servproc:fstat failed. "
2485*1137Sarutz 			    "errno = %d\n"), errno);
24860Sstevel@tonic-gate 			(void) close(didpp->d_data.d_desc.d_descriptor);
24870Sstevel@tonic-gate 			my_door_return((char *)&reterror,
2488*1137Sarutz 			    sizeof (smedia_reterror_t), 0, 0);
24890Sstevel@tonic-gate 		}
24900Sstevel@tonic-gate 		debug(5, "descriptor = %d st_mode = 0x%lx\n",
2491*1137Sarutz 		    didpp->d_data.d_desc.d_descriptor,
2492*1137Sarutz 		    stat.st_mode);
24930Sstevel@tonic-gate 
24940Sstevel@tonic-gate 		/* Obtain the credentials of the user */
24950Sstevel@tonic-gate 		ret_val = door_cred(&door_credentials);
24960Sstevel@tonic-gate 		if (ret_val < 0) {
2497*1137Sarutz 			warning(gettext("main_servproc:door_cred "
2498*1137Sarutz 			    "failed. errno = %d\n"), errno);
24990Sstevel@tonic-gate 			(void) close(didpp->d_data.d_desc.d_descriptor);
25000Sstevel@tonic-gate 			my_door_return((char *)&reterror,
2501*1137Sarutz 			    sizeof (smedia_reterror_t), 0, 0);
25020Sstevel@tonic-gate 		}
25030Sstevel@tonic-gate 		if (ioctl(didpp->d_data.d_desc.d_descriptor, DKIOCINFO,
25040Sstevel@tonic-gate 			&dkinfo) == -1) {
2505*1137Sarutz 			warning(gettext("main_servproc:DKIOCINFO failed. "
2506*1137Sarutz 			    "errno = %d\n"), errno);
25070Sstevel@tonic-gate 			(void) close(didpp->d_data.d_desc.d_descriptor);
25080Sstevel@tonic-gate 			my_door_return((char *)&reterror,
2509*1137Sarutz 			    sizeof (smedia_reterror_t), 0, 0);
25100Sstevel@tonic-gate 		}
25110Sstevel@tonic-gate 
25120Sstevel@tonic-gate 		ddata = (door_data_t *)calloc(1, sizeof (door_data_t));
25130Sstevel@tonic-gate 		if (ddata == NULL) {
2514*1137Sarutz 			warning(gettext("main_servproc:calloc failed. "
2515*1137Sarutz 			    "errno = %d\n"), errno);
25160Sstevel@tonic-gate 			(void) close(didpp->d_data.d_desc.d_descriptor);
25170Sstevel@tonic-gate 			my_door_return((char *)&reterror,
2518*1137Sarutz 			    sizeof (smedia_reterror_t), 0, 0);
25190Sstevel@tonic-gate 		}
25200Sstevel@tonic-gate 		ddata->dd_stat = stat;
25210Sstevel@tonic-gate 		ddata->dd_cred = door_credentials;
25220Sstevel@tonic-gate 		ddata->dd_fd = didpp->d_data.d_desc.d_descriptor;
25230Sstevel@tonic-gate 		ddata->dd_buf = NULL;
25240Sstevel@tonic-gate 		ddata->dd_buf_len = 0;
25250Sstevel@tonic-gate 		ddata->dd_buffd = -1;
25260Sstevel@tonic-gate 		ddata->dd_sector_size = 0;
25270Sstevel@tonic-gate 		ddata->dd_dkinfo = dkinfo;
2528*1137Sarutz 		debug(5, "ddata = 0x%p \n", (void *)ddata);
2529*1137Sarutz 
2530*1137Sarutz 		/* specify a function that'll customize our door threads */
2531*1137Sarutz 		(void) door_server_create(sm_door_server_create);
25320Sstevel@tonic-gate 		debug(5, "door_server_create called.\n");
25330Sstevel@tonic-gate 
25340Sstevel@tonic-gate 		(void) mutex_lock(&ddata->dd_lock);
25350Sstevel@tonic-gate 
2536*1137Sarutz 		/* create Client Door */
2537*1137Sarutz 		ddata->dd_cdoor_descriptor =
2538*1137Sarutz 		    door_create(client_servproc,
2539*1137Sarutz 		    (void *)ddata, DOOR_PRIVATE | DOOR_NO_CANCEL | DOOR_UNREF);
2540*1137Sarutz 
2541*1137Sarutz 		if (ddata->dd_cdoor_descriptor < 0) {
2542*1137Sarutz 			/* then door_create() failed */
2543*1137Sarutz 			int err = errno;
2544*1137Sarutz 
2545*1137Sarutz 			(void) mutex_unlock(&ddata->dd_lock);
2546*1137Sarutz 
2547*1137Sarutz 			warning(gettext("main_servproc: door_create of Client "
2548*1137Sarutz 			    "Door failed = %d\n"), err);
25490Sstevel@tonic-gate 			free(ddata);
2550*1137Sarutz 
2551*1137Sarutz 			/* close target device */
25520Sstevel@tonic-gate 			(void) close(didpp->d_data.d_desc.d_descriptor);
2553*1137Sarutz 			my_door_return((char *)&reterror,
2554*1137Sarutz 			    sizeof (smedia_reterror_t), 0, 0);
25550Sstevel@tonic-gate 		}
2556*1137Sarutz 
2557*1137Sarutz 		/* create Death Door */
2558*1137Sarutz 		ddata->dd_ddoor_descriptor =
2559*1137Sarutz 		    door_create(death_servproc, (void *)ddata,
2560*1137Sarutz 		    DOOR_REFUSE_DESC | DOOR_NO_CANCEL);
2561*1137Sarutz 		if (ddata->dd_ddoor_descriptor < 0) {
2562*1137Sarutz 			warning(gettext("main_servproc: door_create of Death "
2563*1137Sarutz 			    "Door failed = %d\n"), errno);
2564*1137Sarutz 		} else {
2565*1137Sarutz 			(void) door_setparam(ddata->dd_ddoor_descriptor,
2566*1137Sarutz 			    DOOR_PARAM_DATA_MAX, 0);
25670Sstevel@tonic-gate 		}
2568*1137Sarutz 
2569*1137Sarutz 		debug(5, "main_servproc[%d]: Client Door = %d, "
2570*1137Sarutz 		    "Death Door = %d", pthread_self(),
2571*1137Sarutz 		    ddata->dd_cdoor_descriptor, ddata->dd_ddoor_descriptor);
25720Sstevel@tonic-gate 
25730Sstevel@tonic-gate 		audit_init(ddata);
25740Sstevel@tonic-gate 
2575*1137Sarutz 		/* wait until sm_server_thread does door_bind() */
25760Sstevel@tonic-gate 		(void) cond_wait(&ddata->dd_cv_bind, &ddata->dd_lock);
2577*1137Sarutz 
25780Sstevel@tonic-gate 		(void) mutex_unlock(&ddata->dd_lock);
25790Sstevel@tonic-gate 
25800Sstevel@tonic-gate 		(void) mutex_lock(&svcstate_lock);
25810Sstevel@tonic-gate 		svccount++;
25820Sstevel@tonic-gate 		(void) mutex_unlock(&svcstate_lock);
2583*1137Sarutz 
2584*1137Sarutz 		if (ddata->dd_ddoor_descriptor < 0) {
2585*1137Sarutz 			/* Return only the Client Door to the client. */
2586*1137Sarutz 			ddata->dd_cdoor.d_attributes = (DOOR_DESCRIPTOR);
2587*1137Sarutz 			my_door_return((char *)&reterror,
2588*1137Sarutz 			    sizeof (smedia_reterror_t), &ddata->dd_desc[0], 1);
2589*1137Sarutz 		} else {
2590*1137Sarutz 			/*
2591*1137Sarutz 			 * Return the Client Door and Death Door
2592*1137Sarutz 			 * to the client.
2593*1137Sarutz 			 */
2594*1137Sarutz 			debug(5, "retok.cnum = 0x%x\n", retok.cnum);
2595*1137Sarutz 			ddata->dd_cdoor.d_attributes = (DOOR_DESCRIPTOR);
2596*1137Sarutz 			ddata->dd_ddoor.d_attributes = (DOOR_DESCRIPTOR);
2597*1137Sarutz 			my_door_return((char *)&retok,
2598*1137Sarutz 			    sizeof (smedia_reterror_t), &ddata->dd_desc[0], 2);
2599*1137Sarutz 		}
26000Sstevel@tonic-gate 		break;
26010Sstevel@tonic-gate 	}
26020Sstevel@tonic-gate 
2603*1137Sarutz 	debug(10, "exiting main_servproc. \n");
26040Sstevel@tonic-gate 	my_door_return((char *)&reterror, sizeof (smedia_reterror_t), 0, 0);
26050Sstevel@tonic-gate }
26060Sstevel@tonic-gate 
26070Sstevel@tonic-gate /* ARGSUSED */
26080Sstevel@tonic-gate static void
26090Sstevel@tonic-gate term_handler(int sig, siginfo_t *siginfo, void *sigctx)
26100Sstevel@tonic-gate {
26110Sstevel@tonic-gate 	warning(gettext("thread[%d]: Received signal %d. Ignoring it.\n"),
2612*1137Sarutz 	    pthread_self(),
2613*1137Sarutz 	    sig);
26140Sstevel@tonic-gate }
26150Sstevel@tonic-gate 
26160Sstevel@tonic-gate /* ARGSUSED */
26170Sstevel@tonic-gate static void
26180Sstevel@tonic-gate hup_handler(int sig, siginfo_t *siginfo, void *sigctx)
26190Sstevel@tonic-gate {
26200Sstevel@tonic-gate 	warning(gettext("thread[%d]: Received signal %d. Ignoring it.\n"),
2621*1137Sarutz 	    pthread_self(),
2622*1137Sarutz 	    sig);
26230Sstevel@tonic-gate }
26240Sstevel@tonic-gate 
26250Sstevel@tonic-gate /*ARGSUSED*/
26260Sstevel@tonic-gate static void
26270Sstevel@tonic-gate sig_handler(int sig, siginfo_t *siginfo, void *sigctx)
26280Sstevel@tonic-gate {
26290Sstevel@tonic-gate 	warning(gettext("thread[%d]: Received signal %d. Ignoring it.\n"),
2630*1137Sarutz 	    pthread_self(),
2631*1137Sarutz 	    sig);
26320Sstevel@tonic-gate }
26330Sstevel@tonic-gate 
26340Sstevel@tonic-gate /*ARGSUSED*/
26350Sstevel@tonic-gate static void
26360Sstevel@tonic-gate badsig_handler(int sig, siginfo_t *siginfo, void *sigctx)
26370Sstevel@tonic-gate {
26380Sstevel@tonic-gate 	fatal(BADSIG_MSG, pthread_self(), sig, siginfo->si_addr,
2639*1137Sarutz 	    siginfo->si_trapno,
2640*1137Sarutz 	    siginfo->si_pc);
26410Sstevel@tonic-gate }
26420Sstevel@tonic-gate 
26430Sstevel@tonic-gate /*ARGSUSED*/
2644*1137Sarutz static void *
26450Sstevel@tonic-gate init_server(void *argp)
26460Sstevel@tonic-gate {
26470Sstevel@tonic-gate 	int	i, fd;
26480Sstevel@tonic-gate 	struct	sigaction	act;
26490Sstevel@tonic-gate 	struct	rlimit		rlim;
26500Sstevel@tonic-gate 
26510Sstevel@tonic-gate 	debug(10, "init_server  running\n");
26520Sstevel@tonic-gate 
26530Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
26540Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
26550Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
26560Sstevel@tonic-gate #endif
26570Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
26580Sstevel@tonic-gate 
26590Sstevel@tonic-gate 
26600Sstevel@tonic-gate 	if (geteuid() != 0) fatal("Must be root to execute smserverd\n");
26610Sstevel@tonic-gate 
26620Sstevel@tonic-gate 
26630Sstevel@tonic-gate 	/*
26640Sstevel@tonic-gate 	 * setup signal handlers.
26650Sstevel@tonic-gate 	 */
26660Sstevel@tonic-gate 
26670Sstevel@tonic-gate 	for (i = 0; i < N_BADSIGS; i++) {
26680Sstevel@tonic-gate 		act.sa_sigaction = badsig_handler;
26690Sstevel@tonic-gate 		(void) sigemptyset(&act.sa_mask);
26700Sstevel@tonic-gate 		act.sa_flags = SA_SIGINFO;
26710Sstevel@tonic-gate 		if (sigaction(badsigs[i], &act, NULL) == -1)
26720Sstevel@tonic-gate 			warning(gettext(SIGACT_FAILED), strsignal(badsigs[i]),
26730Sstevel@tonic-gate 				strerror(errno));
26740Sstevel@tonic-gate 	}
26750Sstevel@tonic-gate 
26760Sstevel@tonic-gate 	/*
26770Sstevel@tonic-gate 	 * Ignore SIGHUP until all the initialization is done.
26780Sstevel@tonic-gate 	 */
26790Sstevel@tonic-gate 	act.sa_handler = SIG_IGN;
26800Sstevel@tonic-gate 	(void) sigemptyset(&act.sa_mask);
26810Sstevel@tonic-gate 	act.sa_flags = 0;
26820Sstevel@tonic-gate 	if (sigaction(SIGHUP, &act, NULL) == -1)
26830Sstevel@tonic-gate 		warning(gettext(SIGACT_FAILED), strsignal(SIGHUP),
26840Sstevel@tonic-gate 			strerror(errno));
26850Sstevel@tonic-gate 	/*
26860Sstevel@tonic-gate 	 * Increase file descriptor limit to the most it can possibly
26870Sstevel@tonic-gate 	 * be.
26880Sstevel@tonic-gate 	 */
26890Sstevel@tonic-gate 	if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
26900Sstevel@tonic-gate 		warning(gettext("getrlimit for fd's failed; %m\n"));
26910Sstevel@tonic-gate 	}
26920Sstevel@tonic-gate 
26930Sstevel@tonic-gate 	rlim.rlim_cur = rlim.rlim_max;
26940Sstevel@tonic-gate 
26950Sstevel@tonic-gate 	if (setrlimit(RLIMIT_NOFILE, &rlim) < 0) {
26960Sstevel@tonic-gate 		warning(gettext("setrlimit for fd's failed; %m\n"));
26970Sstevel@tonic-gate 	}
26980Sstevel@tonic-gate 
2699*1137Sarutz 	server_door = door_create(main_servproc, (void *)&server_data, 0);
27000Sstevel@tonic-gate 	if (server_door == -1) {
27010Sstevel@tonic-gate 		debug(1, "main door_create");
27020Sstevel@tonic-gate 		exit(1);
27030Sstevel@tonic-gate 	}
27040Sstevel@tonic-gate 
27050Sstevel@tonic-gate 	(void) unlink(smedia_service);
27060Sstevel@tonic-gate 	fd = open(smedia_service, O_RDWR|O_CREAT|O_EXCL, 0644);
27070Sstevel@tonic-gate 	if (fd < 0) {
27080Sstevel@tonic-gate 		debug(5, "could not open %s.\n", smedia_service);
27090Sstevel@tonic-gate 		exit(1);
27100Sstevel@tonic-gate 	}
27110Sstevel@tonic-gate 	(void) close(fd);
27120Sstevel@tonic-gate 	server_fd = fattach(server_door, smedia_service);
27130Sstevel@tonic-gate 	if (server_fd == -1) {
27140Sstevel@tonic-gate 		debug(1, "main fattach");
27150Sstevel@tonic-gate 		exit(1);
27160Sstevel@tonic-gate 	}
27170Sstevel@tonic-gate 	server_data.sd_door = server_door;
27180Sstevel@tonic-gate 	server_data.sd_fd = server_fd;
27190Sstevel@tonic-gate 
27200Sstevel@tonic-gate 	/*
27210Sstevel@tonic-gate 	 * setup signal handlers for post-init
27220Sstevel@tonic-gate 	 */
27230Sstevel@tonic-gate 
27240Sstevel@tonic-gate 	act.sa_sigaction = hup_handler;
27250Sstevel@tonic-gate 	(void) sigemptyset(&act.sa_mask);
27260Sstevel@tonic-gate 	act.sa_flags = SA_SIGINFO;
27270Sstevel@tonic-gate 	if (sigaction(SIGHUP, &act, NULL) == -1)
27280Sstevel@tonic-gate 		warning(gettext(SIGACT_FAILED), strsignal(SIGHUP),
27290Sstevel@tonic-gate 		    strerror(errno));
27300Sstevel@tonic-gate 
27310Sstevel@tonic-gate 	act.sa_sigaction = term_handler;
27320Sstevel@tonic-gate 	(void) sigemptyset(&act.sa_mask);
27330Sstevel@tonic-gate 	act.sa_flags = SA_SIGINFO;
27340Sstevel@tonic-gate 	if (sigaction(SIGTERM, &act, NULL) == -1)
27350Sstevel@tonic-gate 		warning(gettext(SIGACT_FAILED), strsignal(SIGTERM),
27360Sstevel@tonic-gate 		    strerror(errno));
27370Sstevel@tonic-gate 
27380Sstevel@tonic-gate 	act.sa_sigaction = sig_handler;
27390Sstevel@tonic-gate 	(void) sigemptyset(&act.sa_mask);
27400Sstevel@tonic-gate 	act.sa_flags = SA_SIGINFO;
27410Sstevel@tonic-gate 	if (sigaction(SIGINT, &act, NULL) == -1)
27420Sstevel@tonic-gate 		warning(gettext(SIGACT_FAILED), strsignal(SIGHUP),
27430Sstevel@tonic-gate 		    strerror(errno));
27440Sstevel@tonic-gate 
27450Sstevel@tonic-gate 	act.sa_sigaction = sig_handler;
27460Sstevel@tonic-gate 	(void) sigemptyset(&act.sa_mask);
27470Sstevel@tonic-gate 	act.sa_flags = SA_SIGINFO;
27480Sstevel@tonic-gate 	if (sigaction(SIGQUIT, &act, NULL) == -1)
27490Sstevel@tonic-gate 		warning(gettext(SIGACT_FAILED), strsignal(SIGHUP),
27500Sstevel@tonic-gate 		    strerror(errno));
27510Sstevel@tonic-gate 	debug(10, "init_server completed successfully\n");
27520Sstevel@tonic-gate 
27530Sstevel@tonic-gate 	server_data.sd_init_state = INIT_DONE;
27540Sstevel@tonic-gate 	return (NULL);
27550Sstevel@tonic-gate }
27560Sstevel@tonic-gate 
27570Sstevel@tonic-gate static int
27580Sstevel@tonic-gate server_exists()
27590Sstevel@tonic-gate {
27600Sstevel@tonic-gate 	door_arg_t		darg;
27610Sstevel@tonic-gate 	smedia_reqping_t	req_ping;
27620Sstevel@tonic-gate 	smedia_retping_t	*ret_ping;
27630Sstevel@tonic-gate 	int			doorh;
27640Sstevel@tonic-gate 	door_info_t		dinfo;
27650Sstevel@tonic-gate 	char    rbuf[sizeof (smedia_services_t) + sizeof (door_desc_t)];
27660Sstevel@tonic-gate 
27670Sstevel@tonic-gate 	doorh = open(smedia_service, O_RDONLY);
27680Sstevel@tonic-gate 	if (doorh < 0)
27690Sstevel@tonic-gate 		return (0);
27700Sstevel@tonic-gate 	if (door_info(doorh, &dinfo) < 0) {
27710Sstevel@tonic-gate 		(void) close(doorh);
27720Sstevel@tonic-gate 		return (0);
27730Sstevel@tonic-gate 	}
27740Sstevel@tonic-gate 	if (dinfo.di_attributes & DOOR_REVOKED) {
27750Sstevel@tonic-gate 		(void) close(doorh);
27760Sstevel@tonic-gate 		return (0);
27770Sstevel@tonic-gate 	}
27780Sstevel@tonic-gate 
27790Sstevel@tonic-gate 	req_ping.cnum = SMEDIA_CNUM_PING;
27800Sstevel@tonic-gate 
27810Sstevel@tonic-gate 	darg.data_ptr = (char *)&req_ping;
27820Sstevel@tonic-gate 	darg.data_size = sizeof (smedia_reqping_t);
27830Sstevel@tonic-gate 	darg.desc_ptr = NULL;
27840Sstevel@tonic-gate 	darg.desc_num = 0;
27850Sstevel@tonic-gate 	darg.rbuf = rbuf;
27860Sstevel@tonic-gate 	darg.rsize = sizeof (rbuf);
27870Sstevel@tonic-gate 
27880Sstevel@tonic-gate 	if (door_call(doorh, &darg) < 0) {
27890Sstevel@tonic-gate 		(void) close(doorh);
27900Sstevel@tonic-gate 		return (0);
27910Sstevel@tonic-gate 	}
27920Sstevel@tonic-gate 	ret_ping = (smedia_retping_t *)((void *)darg.data_ptr);
27930Sstevel@tonic-gate 	if (ret_ping->cnum != SMEDIA_CNUM_PING) {
27940Sstevel@tonic-gate 		(void) close(doorh);
27950Sstevel@tonic-gate 		return (0);
27960Sstevel@tonic-gate 	}
27970Sstevel@tonic-gate 
27980Sstevel@tonic-gate 	(void) close(doorh);
27990Sstevel@tonic-gate 	return (1);
28000Sstevel@tonic-gate }
28010Sstevel@tonic-gate 
28020Sstevel@tonic-gate static int
28030Sstevel@tonic-gate get_run_level()
28040Sstevel@tonic-gate {
28050Sstevel@tonic-gate 	int	run_level;
28060Sstevel@tonic-gate 	struct utmpx	*utmpp;
28070Sstevel@tonic-gate 
28080Sstevel@tonic-gate 	setutxent();
28090Sstevel@tonic-gate 	while ((utmpp = getutxent()) != NULL) {
28100Sstevel@tonic-gate 		if (utmpp->ut_type == RUN_LVL) {
28110Sstevel@tonic-gate 			run_level = atoi(
28120Sstevel@tonic-gate 				&utmpp->ut_line[strlen("run-level ")]);
28130Sstevel@tonic-gate 		}
28140Sstevel@tonic-gate 	}
28150Sstevel@tonic-gate 	return (run_level);
28160Sstevel@tonic-gate }
28170Sstevel@tonic-gate 
28180Sstevel@tonic-gate /*ARGSUSED*/
28190Sstevel@tonic-gate static void *
28200Sstevel@tonic-gate closedown(void *arg)
28210Sstevel@tonic-gate {
28220Sstevel@tonic-gate 
28230Sstevel@tonic-gate 	int	current_run_level;
28240Sstevel@tonic-gate 
28250Sstevel@tonic-gate 	/*CONSTCOND*/
28260Sstevel@tonic-gate #ifndef lint
28270Sstevel@tonic-gate 	while (1) {
28280Sstevel@tonic-gate #endif
28290Sstevel@tonic-gate 		(void) sleep(SVC_CLOSEDOWN/2);
28300Sstevel@tonic-gate 
28310Sstevel@tonic-gate 		/*
28320Sstevel@tonic-gate 		 * If the server was started at init level 1
28330Sstevel@tonic-gate 		 * and the current init level is 1 then
28340Sstevel@tonic-gate 		 * do not exit from server. This server will run
28350Sstevel@tonic-gate 		 * until it is explicitly stopped by the user.
28360Sstevel@tonic-gate 		 */
28370Sstevel@tonic-gate 		if (svcstart_level == 1) {
28380Sstevel@tonic-gate 			current_run_level = get_run_level();
28390Sstevel@tonic-gate 			if (current_run_level == 1)
28400Sstevel@tonic-gate #ifndef lint
28410Sstevel@tonic-gate 				continue;
28420Sstevel@tonic-gate #else
28430Sstevel@tonic-gate 				return (NULL);
28440Sstevel@tonic-gate #endif
28450Sstevel@tonic-gate 			/*
28460Sstevel@tonic-gate 			 * who ever started the server at level 1 has
28470Sstevel@tonic-gate 			 * forgotten to stop the server. we will kill ourself.
28480Sstevel@tonic-gate 			 */
28490Sstevel@tonic-gate 			debug(5,
28500Sstevel@tonic-gate 			"Terminating the server started at init level 1\n");
28510Sstevel@tonic-gate 			exit(0);
28520Sstevel@tonic-gate 		}
28530Sstevel@tonic-gate 
28540Sstevel@tonic-gate 		if (mutex_trylock(&svcstate_lock) != 0)
28550Sstevel@tonic-gate #ifndef lint
28560Sstevel@tonic-gate 			continue;
28570Sstevel@tonic-gate #else
28580Sstevel@tonic-gate 			return (NULL);
28590Sstevel@tonic-gate #endif
28600Sstevel@tonic-gate 		if (svcstate == _IDLE && svccount == 0) {
28610Sstevel@tonic-gate 			int size;
28620Sstevel@tonic-gate 			int i, openfd = 0;
28630Sstevel@tonic-gate 
28640Sstevel@tonic-gate 			size = svc_max_pollfd;
28650Sstevel@tonic-gate 			for (i = 0; i < size && openfd < 2; i++)
28660Sstevel@tonic-gate 				if (svc_pollfd[i].fd >= 0)
28670Sstevel@tonic-gate 					openfd++;
28680Sstevel@tonic-gate 			if (openfd <= 1) {
28690Sstevel@tonic-gate 				debug(5,
28700Sstevel@tonic-gate 				"Exiting the server from closedown routine.\n");
28710Sstevel@tonic-gate 				exit(0);
28720Sstevel@tonic-gate 			}
28730Sstevel@tonic-gate 		} else
28740Sstevel@tonic-gate 			svcstate = _IDLE;
28750Sstevel@tonic-gate 
28760Sstevel@tonic-gate 		(void) mutex_unlock(&svcstate_lock);
28770Sstevel@tonic-gate #ifndef lint
28780Sstevel@tonic-gate 	}
28790Sstevel@tonic-gate #else
28800Sstevel@tonic-gate 	return (NULL);
28810Sstevel@tonic-gate #endif
28820Sstevel@tonic-gate 
28830Sstevel@tonic-gate }
28840Sstevel@tonic-gate 
28850Sstevel@tonic-gate static void
28860Sstevel@tonic-gate usage()
28870Sstevel@tonic-gate {
28880Sstevel@tonic-gate 	warning(gettext("usage: %s [-L loglevel] level of debug information\n"),
28890Sstevel@tonic-gate 		prog_name);
28900Sstevel@tonic-gate }
28910Sstevel@tonic-gate 
28920Sstevel@tonic-gate 
28930Sstevel@tonic-gate /*ARGSUSED*/
2894796Smathue int
28950Sstevel@tonic-gate main(int argc, char **argv)
28960Sstevel@tonic-gate {
28970Sstevel@tonic-gate 	int c;
28980Sstevel@tonic-gate 	pthread_attr_t	attr;
28990Sstevel@tonic-gate 
29000Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
29010Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
29020Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
29030Sstevel@tonic-gate #endif
29040Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
29050Sstevel@tonic-gate 
29060Sstevel@tonic-gate 	prog_name = argv[0];
29070Sstevel@tonic-gate 
29080Sstevel@tonic-gate 	(void) sigset(SIGPIPE, SIG_IGN);
29090Sstevel@tonic-gate 
29100Sstevel@tonic-gate 	while ((c = getopt(argc, argv, "L:")) != -1) {
29110Sstevel@tonic-gate 		switch (c) {
29120Sstevel@tonic-gate 		case 'L':
29130Sstevel@tonic-gate 			debug_level = atoi((char *)optarg);
29140Sstevel@tonic-gate 			break;
29150Sstevel@tonic-gate 		default:
29160Sstevel@tonic-gate 			usage();
29170Sstevel@tonic-gate 			break;
29180Sstevel@tonic-gate 		}
29190Sstevel@tonic-gate 	}
29200Sstevel@tonic-gate 
29210Sstevel@tonic-gate 	/*
29220Sstevel@tonic-gate 	 * If stdin looks like a TLI endpoint, we assume
29230Sstevel@tonic-gate 	 * that we were started by a port monitor. If
29240Sstevel@tonic-gate 	 * t_getstate fails with TBADF, this is not a
29250Sstevel@tonic-gate 	 * TLI endpoint.
29260Sstevel@tonic-gate 	 */
29270Sstevel@tonic-gate 	if (t_getstate(0) != -1 || t_errno != TBADF) {
29280Sstevel@tonic-gate 		char *netid;
29290Sstevel@tonic-gate 		struct netconfig *nconf = NULL;
29300Sstevel@tonic-gate 		SVCXPRT *transp;
29310Sstevel@tonic-gate 		int pmclose;
29320Sstevel@tonic-gate 
29330Sstevel@tonic-gate 		openlog(prog_name, LOG_PID, LOG_DAEMON);
29340Sstevel@tonic-gate 
29350Sstevel@tonic-gate 		debug(1, gettext("server started by port monitor.\n"));
29360Sstevel@tonic-gate 		if ((netid = getenv("NLSPROVIDER")) == NULL) {
29370Sstevel@tonic-gate 		/* started from inetd */
29380Sstevel@tonic-gate 			pmclose = 1;
29390Sstevel@tonic-gate 		} else {
29400Sstevel@tonic-gate 			if ((nconf = getnetconfigent(netid)) == NULL)
29410Sstevel@tonic-gate 				syslog(LOG_ERR, gettext(
29420Sstevel@tonic-gate 					"cannot get transport info"));
29430Sstevel@tonic-gate 
29440Sstevel@tonic-gate 			pmclose = (t_getstate(0) != T_DATAXFER);
29450Sstevel@tonic-gate 		}
29460Sstevel@tonic-gate 		if ((transp = svc_tli_create(0, nconf, NULL, 0, 0)) == NULL) {
29470Sstevel@tonic-gate 			syslog(LOG_ERR, gettext("cannot create server handle"));
29480Sstevel@tonic-gate 			exit(1);
29490Sstevel@tonic-gate 		}
29500Sstevel@tonic-gate 		if (nconf)
29510Sstevel@tonic-gate 			freenetconfigent(nconf);
29520Sstevel@tonic-gate 		if (!svc_reg(transp, SMSERVERPROG, SMSERVERVERS,
29530Sstevel@tonic-gate 			smserverprog_1, 0)) {
29540Sstevel@tonic-gate 			syslog(LOG_ERR, gettext(
29550Sstevel@tonic-gate 			"unable to register (SMSERVERPROG, SMSERVERVERS)."));
29560Sstevel@tonic-gate 			exit(1);
29570Sstevel@tonic-gate 		}
29580Sstevel@tonic-gate 		svcstart_level = get_run_level();
29590Sstevel@tonic-gate 		if (pmclose) {
29600Sstevel@tonic-gate 			(void) pthread_attr_init(&attr);
29610Sstevel@tonic-gate 			(void) pthread_attr_setscope(&attr,
29620Sstevel@tonic-gate 				PTHREAD_SCOPE_SYSTEM | PTHREAD_CREATE_DETACHED);
29630Sstevel@tonic-gate 			if (pthread_create(NULL, &attr, closedown, NULL) != 0) {
29640Sstevel@tonic-gate 				syslog(LOG_ERR, gettext(
29650Sstevel@tonic-gate 					"cannot create closedown thread"));
29660Sstevel@tonic-gate 				exit(1);
29670Sstevel@tonic-gate 			}
29680Sstevel@tonic-gate 			(void) pthread_attr_destroy(&attr);
29690Sstevel@tonic-gate 		}
29700Sstevel@tonic-gate 		svc_run();
29710Sstevel@tonic-gate 		exit(1);
29720Sstevel@tonic-gate 		/* NOTREACHED */
29730Sstevel@tonic-gate 	} else {
29740Sstevel@tonic-gate 		/*
29750Sstevel@tonic-gate 		 * Started by library or manually.
29760Sstevel@tonic-gate 		 */
29770Sstevel@tonic-gate 		/*
29780Sstevel@tonic-gate 		 * Check to see if the server is already running.
29790Sstevel@tonic-gate 		 * There is no need to log messages in the syslog file
29800Sstevel@tonic-gate 		 * because server will get launched each time libsmedia
29810Sstevel@tonic-gate 		 * library calls are made at init 1 level.
29820Sstevel@tonic-gate 		 * We ensure that only one copy will run.
29830Sstevel@tonic-gate 		 */
29840Sstevel@tonic-gate 		debug(1, gettext("server started manually.\n"));
29850Sstevel@tonic-gate 		if (server_exists()) {
29860Sstevel@tonic-gate 			exit(0);
29870Sstevel@tonic-gate 		}
29880Sstevel@tonic-gate 		svcstart_level = get_run_level();
29890Sstevel@tonic-gate 		(void) pthread_attr_init(&attr);
29900Sstevel@tonic-gate 		(void) pthread_attr_setscope(&attr,
29910Sstevel@tonic-gate 			PTHREAD_SCOPE_SYSTEM | PTHREAD_CREATE_DETACHED);
29920Sstevel@tonic-gate 		if (pthread_create(NULL, &attr, closedown, NULL) != 0) {
29930Sstevel@tonic-gate 			syslog(LOG_ERR, gettext(
29940Sstevel@tonic-gate 				"cannot create closedown thread"));
29950Sstevel@tonic-gate 			exit(1);
29960Sstevel@tonic-gate 		}
29970Sstevel@tonic-gate 		(void) pthread_attr_destroy(&attr);
29980Sstevel@tonic-gate 		(void) init_server(NULL);
29990Sstevel@tonic-gate 		for (;;) (void) pause();
30000Sstevel@tonic-gate 	}
3001796Smathue 	return (0);
30020Sstevel@tonic-gate }
30030Sstevel@tonic-gate 
30040Sstevel@tonic-gate 
30050Sstevel@tonic-gate /*ARGSUSED*/
30060Sstevel@tonic-gate static int32_t
30070Sstevel@tonic-gate scsi_floppy_write_protect(int32_t fd, smwp_state_t *wp)
30080Sstevel@tonic-gate {
30090Sstevel@tonic-gate 	debug(5, "Invalid mode\n");
30100Sstevel@tonic-gate 	errno = ENOTSUP;
30110Sstevel@tonic-gate 
30120Sstevel@tonic-gate 	return (-1);
30130Sstevel@tonic-gate }
30140Sstevel@tonic-gate 
30150Sstevel@tonic-gate /*
30160Sstevel@tonic-gate  * Generate standard geometry information for SCSI floppy devices. And
30170Sstevel@tonic-gate  * register the geometry with the SCSI driver. This will expand as more
30180Sstevel@tonic-gate  * formats are added.
30190Sstevel@tonic-gate  */
30200Sstevel@tonic-gate 
30210Sstevel@tonic-gate /*ARGSUSED*/
30220Sstevel@tonic-gate static int32_t
30230Sstevel@tonic-gate get_floppy_geom(int32_t fd, uint32_t capacity, struct dk_geom *dkgeom)
30240Sstevel@tonic-gate {
30250Sstevel@tonic-gate 
30260Sstevel@tonic-gate 
30270Sstevel@tonic-gate 	debug(5, "get_floppy_geom: capacity = 0x%x\n", capacity);
30280Sstevel@tonic-gate 
30290Sstevel@tonic-gate 	switch (capacity) {
30300Sstevel@tonic-gate 
30310Sstevel@tonic-gate 		case 0x5A0:
30320Sstevel@tonic-gate 			/* Double Density 720K */
30330Sstevel@tonic-gate 			dkgeom->dkg_pcyl = 80;
30340Sstevel@tonic-gate 			dkgeom->dkg_ncyl = 80;
30350Sstevel@tonic-gate 			dkgeom->dkg_nhead = 2;
30360Sstevel@tonic-gate 			dkgeom->dkg_nsect = 9;
30370Sstevel@tonic-gate 			break;
30380Sstevel@tonic-gate 		case 0x4D0:
30390Sstevel@tonic-gate 			/* High Density 1.25MB */
30400Sstevel@tonic-gate 			dkgeom->dkg_pcyl = 77;
30410Sstevel@tonic-gate 			dkgeom->dkg_ncyl = 77;
30420Sstevel@tonic-gate 			dkgeom->dkg_nhead = 2;
30430Sstevel@tonic-gate 			dkgeom->dkg_nsect = 9;
30440Sstevel@tonic-gate 			break;
30450Sstevel@tonic-gate 		case 0xB40:
30460Sstevel@tonic-gate 			/* High Density 1.44MB */
30470Sstevel@tonic-gate 
30480Sstevel@tonic-gate 			dkgeom->dkg_pcyl = 80;
30490Sstevel@tonic-gate 			dkgeom->dkg_ncyl = 80;
30500Sstevel@tonic-gate 			dkgeom->dkg_nhead = 2;
30510Sstevel@tonic-gate 			dkgeom->dkg_nsect = 18;
30520Sstevel@tonic-gate 			break;
30530Sstevel@tonic-gate 		case 0x3C300:
30540Sstevel@tonic-gate 			/* Ultra High density ls-120 120MB */
30550Sstevel@tonic-gate 			dkgeom->dkg_pcyl = 963;
30560Sstevel@tonic-gate 			dkgeom->dkg_ncyl = 963;
30570Sstevel@tonic-gate 			dkgeom->dkg_nhead = 8;
30580Sstevel@tonic-gate 			dkgeom->dkg_nsect = 32;
30590Sstevel@tonic-gate 			break;
30600Sstevel@tonic-gate 		default:
30610Sstevel@tonic-gate 			debug(5, "unknown capacity type %d\n", capacity);
30620Sstevel@tonic-gate 			return (-1);
30630Sstevel@tonic-gate 
30640Sstevel@tonic-gate 	}
30650Sstevel@tonic-gate 	debug(5, "get_floppy_geom: setting cyl = %d, nsect = %d, head = %d",
30660Sstevel@tonic-gate 		dkgeom->dkg_pcyl, dkgeom->dkg_nhead, dkgeom->dkg_nsect);
30670Sstevel@tonic-gate 	return (0);
30680Sstevel@tonic-gate 
30690Sstevel@tonic-gate }
30700Sstevel@tonic-gate /* ARGSUSED */
3071*1137Sarutz static int32_t
30720Sstevel@tonic-gate scsi_floppy_format(int32_t fd, uint_t flavor, uint_t mode)
30730Sstevel@tonic-gate {
30740Sstevel@tonic-gate 	struct uscsi_cmd ucmd;
30750Sstevel@tonic-gate 	uchar_t		cdb[12];
30760Sstevel@tonic-gate 	int32_t		ret_val;
30770Sstevel@tonic-gate 	uint32_t	capacity, blocksize;
30780Sstevel@tonic-gate 	uchar_t		data[12];
30790Sstevel@tonic-gate 	char 		rq_data[RQ_LEN];
30800Sstevel@tonic-gate 	int		i;
30810Sstevel@tonic-gate 	struct dk_geom	dkgeom;
30820Sstevel@tonic-gate 
30830Sstevel@tonic-gate 	debug(5, "scsi_floppy_format:\n");
30840Sstevel@tonic-gate 
30850Sstevel@tonic-gate 	if ((mode != SM_FORMAT_IMMEDIATE) && (mode != SM_FORMAT_BLOCKED)) {
30860Sstevel@tonic-gate 		errno = ENOTSUP;
30870Sstevel@tonic-gate 
30880Sstevel@tonic-gate 		return (-1);
30890Sstevel@tonic-gate 	}
30900Sstevel@tonic-gate 
30910Sstevel@tonic-gate 	switch (flavor) {
30920Sstevel@tonic-gate 		case SM_FORMAT_QUICK :
30930Sstevel@tonic-gate 			debug(1, "Format not supported\n");
30940Sstevel@tonic-gate 			errno = ENOTSUP;
30950Sstevel@tonic-gate 			return (-1);
30960Sstevel@tonic-gate 		case SM_FORMAT_FORCE :
30970Sstevel@tonic-gate 			break;
30980Sstevel@tonic-gate 		case SM_FORMAT_LONG :
30990Sstevel@tonic-gate 			break;
31000Sstevel@tonic-gate 
31010Sstevel@tonic-gate 		default :
31020Sstevel@tonic-gate 			debug(1, "Format option not specified!!\n");
31030Sstevel@tonic-gate 			errno = ENOTSUP;
31040Sstevel@tonic-gate 			return (-1);
31050Sstevel@tonic-gate 	}
31060Sstevel@tonic-gate 
31070Sstevel@tonic-gate 	ret_val = get_media_capacity(fd, &capacity, &blocksize);
31080Sstevel@tonic-gate 
31090Sstevel@tonic-gate 	if (capacity >= 0x3C300) {
31100Sstevel@tonic-gate 		/*
31110Sstevel@tonic-gate 		 * It's an LS-120 media, it does not support track
31120Sstevel@tonic-gate 		 * formatting.
31130Sstevel@tonic-gate 		 */
31140Sstevel@tonic-gate 		return (scsi_ls120_format(fd, flavor, capacity, blocksize));
31150Sstevel@tonic-gate 	}
31160Sstevel@tonic-gate 
31170Sstevel@tonic-gate 	ret_val = get_floppy_geom(fd, capacity, &dkgeom);
31180Sstevel@tonic-gate 		if (ret_val) {
31190Sstevel@tonic-gate 			errno = ENOTSUP;
31200Sstevel@tonic-gate 			return (-1);
31210Sstevel@tonic-gate 		}
31220Sstevel@tonic-gate 
31230Sstevel@tonic-gate 	(void) memset((void *)&data, 0, sizeof (data));
31240Sstevel@tonic-gate 	(void) memset((void *)&ucmd, 0, sizeof (ucmd));
31250Sstevel@tonic-gate 	(void) memset((void *)&cdb, 0, sizeof (cdb));
31260Sstevel@tonic-gate 
31270Sstevel@tonic-gate 	/* retrieve size discriptor of inserted media */
31280Sstevel@tonic-gate 	cdb[0] = SCMD_FORMAT;	/* format */
31290Sstevel@tonic-gate 
31300Sstevel@tonic-gate 	/*
31310Sstevel@tonic-gate 	 * Defect list sent by initiator is a complete list of defects.
31320Sstevel@tonic-gate 	 */
31330Sstevel@tonic-gate 
31340Sstevel@tonic-gate 	cdb[1] = (FMTDATA | 0x7);
31350Sstevel@tonic-gate 
31360Sstevel@tonic-gate 	cdb[8] = 0xC;   /* parameter list length */
31370Sstevel@tonic-gate 	data[3] = 0x8;	/* should be always 8 */
31380Sstevel@tonic-gate 
31390Sstevel@tonic-gate 	data[4] = (uchar_t)(capacity >> 24);
31400Sstevel@tonic-gate 	data[5] = (uchar_t)(capacity >> 16);
31410Sstevel@tonic-gate 	data[6] = (uchar_t)(capacity >> 8);
31420Sstevel@tonic-gate 	data[7] = (uchar_t)capacity;
31430Sstevel@tonic-gate 
31440Sstevel@tonic-gate 	data[9] = (uchar_t)(blocksize >> 16);
31450Sstevel@tonic-gate 	data[10] = (uchar_t)(blocksize >> 8);
31460Sstevel@tonic-gate 	data[11] = (uchar_t)blocksize;
31470Sstevel@tonic-gate 
31480Sstevel@tonic-gate 	ucmd.uscsi_cdb = (caddr_t)&cdb;
31490Sstevel@tonic-gate 	ucmd.uscsi_cdblen = CDB_GROUP5;
31500Sstevel@tonic-gate 	ucmd.uscsi_bufaddr = (caddr_t)data;
31510Sstevel@tonic-gate 	ucmd.uscsi_buflen = sizeof (data);
31520Sstevel@tonic-gate 	ucmd.uscsi_timeout = 0x15;
31530Sstevel@tonic-gate 	ucmd.uscsi_rqlen = RQ_LEN;
31540Sstevel@tonic-gate 	ucmd.uscsi_rqbuf = rq_data;
31550Sstevel@tonic-gate 
31560Sstevel@tonic-gate 	debug(5, "cdb: %x %x %x ... %x", cdb[0], cdb[1], cdb[2], cdb[8]);
31570Sstevel@tonic-gate 	debug(5, "data: %x %x %x %x\n", data[0], data[1], data[2], data[3]);
31580Sstevel@tonic-gate 	debug(5, "    : %x %x %x %x\n", data[4], data[5], data[6], data[7]);
31590Sstevel@tonic-gate 	debug(5, "    : %x %x %x %x\n", data[8], data[9], data[10], data[11]);
31600Sstevel@tonic-gate 
31610Sstevel@tonic-gate 	for (i = 0; i < dkgeom.dkg_pcyl; i++) {	/* number of tracks */
31620Sstevel@tonic-gate 		data[1] = (0xb0 | FOV);
31630Sstevel@tonic-gate 		cdb[2] = i;
31640Sstevel@tonic-gate 
31650Sstevel@tonic-gate 		(void) fflush(stdout);
31660Sstevel@tonic-gate 		ret_val = do_uscsi_cmd(fd, &ucmd, USCSI_WRITE|USCSI_RQENABLE);
31670Sstevel@tonic-gate 		info("format side 0 returned : 0x%x\n", ret_val);
31680Sstevel@tonic-gate 
31690Sstevel@tonic-gate 		if (ret_val || ucmd.uscsi_status) {
31700Sstevel@tonic-gate 			debug(5, "Retrieving media info failed: %d - %d\n",
31710Sstevel@tonic-gate 			    ret_val, ucmd.uscsi_status);
31720Sstevel@tonic-gate 			if ((rq_data[2] == KEY_DATA_PROTECT) &&
31730Sstevel@tonic-gate 			    (rq_data[12] == 0x30) && (rq_data[13] == 0)) {
31740Sstevel@tonic-gate 				debug(5, "Invalid command for media\n");
31750Sstevel@tonic-gate 				errno = EINVAL;
31760Sstevel@tonic-gate 			}
31770Sstevel@tonic-gate 
31780Sstevel@tonic-gate 			if ((rq_data[2] == KEY_NOT_READY) &&
31790Sstevel@tonic-gate 			    (rq_data[12] == 0x30)) {
31800Sstevel@tonic-gate 				debug(5, "Incompatible media.\n");
31810Sstevel@tonic-gate 				errno = EINVAL;
31820Sstevel@tonic-gate 			}
31830Sstevel@tonic-gate 
31840Sstevel@tonic-gate 			return (-1);
31850Sstevel@tonic-gate 		}
31860Sstevel@tonic-gate 		data[1] = (0xb0 | FOV) + 1;
31870Sstevel@tonic-gate 		ret_val = do_uscsi_cmd(fd, &ucmd, USCSI_WRITE|USCSI_RQENABLE);
31880Sstevel@tonic-gate 		info("format side 1 returned : 0x%x\n", ret_val);
31890Sstevel@tonic-gate 
31900Sstevel@tonic-gate 		if (ret_val || ucmd.uscsi_status) {
31910Sstevel@tonic-gate 			debug(5, "Retrieving media info failed: %d - %d\n",
31920Sstevel@tonic-gate 			    ret_val, ucmd.uscsi_status);
31930Sstevel@tonic-gate 			if ((rq_data[2] == KEY_DATA_PROTECT) &&
31940Sstevel@tonic-gate 			    (rq_data[12] == 0x30) && (rq_data[13] == 0)) {
31950Sstevel@tonic-gate 				(void) info("Invalid command for media\n");
31960Sstevel@tonic-gate 				errno = EINVAL;
31970Sstevel@tonic-gate 			}
31980Sstevel@tonic-gate 
31990Sstevel@tonic-gate 			if ((rq_data[2] == KEY_NOT_READY) &&
32000Sstevel@tonic-gate 			    (rq_data[12] == 0x30)) {
32010Sstevel@tonic-gate 				debug(5, "Incompatible media.\n");
32020Sstevel@tonic-gate 				errno = EINVAL;
32030Sstevel@tonic-gate 			}
32040Sstevel@tonic-gate 
32050Sstevel@tonic-gate 			return (-1);
32060Sstevel@tonic-gate 		}
32070Sstevel@tonic-gate 	}
32080Sstevel@tonic-gate 
32090Sstevel@tonic-gate 	debug(5, "formatting done!");
32100Sstevel@tonic-gate 	return (0);
32110Sstevel@tonic-gate }
32120Sstevel@tonic-gate 
32130Sstevel@tonic-gate 
32140Sstevel@tonic-gate /* ARGSUSED */
3215*1137Sarutz static int32_t
32160Sstevel@tonic-gate scsi_floppy_media_status(int32_t fd)
32170Sstevel@tonic-gate {
32180Sstevel@tonic-gate 	struct mode_header_g1 modeh;
32190Sstevel@tonic-gate 	struct uscsi_cmd ucmd;
32200Sstevel@tonic-gate 	uchar_t cdb[10];
32210Sstevel@tonic-gate 	int32_t ret_val;
32220Sstevel@tonic-gate 	int32_t cur_status;
32230Sstevel@tonic-gate 	char rq_data[RQ_LEN];
32240Sstevel@tonic-gate 
32250Sstevel@tonic-gate 	debug(5, "SCSI MEDIA STATUS CALLED \n");
32260Sstevel@tonic-gate 
32270Sstevel@tonic-gate 	(void) memset((void *) &modeh, 0, sizeof (modeh));
32280Sstevel@tonic-gate 	(void) memset((void *) &ucmd, 0, sizeof (ucmd));
32290Sstevel@tonic-gate 	(void) memset(cdb, 0, sizeof (cdb));
32300Sstevel@tonic-gate 	/*
32310Sstevel@tonic-gate 	 * issue 10 byte mode sense (0x5A)
32320Sstevel@tonic-gate 	 */
32330Sstevel@tonic-gate 	cdb[0] = SCMD_MODE_SENSE_G1;
32340Sstevel@tonic-gate 	cdb[7] = sizeof (modeh) >> 8;
32350Sstevel@tonic-gate 	cdb[8] = sizeof (modeh) & 0xff;
32360Sstevel@tonic-gate 
32370Sstevel@tonic-gate 	ucmd.uscsi_cdb = (caddr_t)cdb;
32380Sstevel@tonic-gate 	ucmd.uscsi_cdblen = CDB_GROUP1;
32390Sstevel@tonic-gate 	ucmd.uscsi_bufaddr = (caddr_t)&modeh;
32400Sstevel@tonic-gate 	ucmd.uscsi_buflen = sizeof (modeh);
32410Sstevel@tonic-gate 	ucmd.uscsi_timeout = 120;	/* If 0, HBA hangs forever */
32420Sstevel@tonic-gate 	ucmd.uscsi_rqlen = RQ_LEN;
32430Sstevel@tonic-gate 	ucmd.uscsi_rqbuf = rq_data;
32440Sstevel@tonic-gate 	ret_val = do_uscsi_cmd(fd, &ucmd, USCSI_READ|USCSI_RQENABLE);
32450Sstevel@tonic-gate 	if (ret_val || ucmd.uscsi_status) {
32460Sstevel@tonic-gate 		/*
32470Sstevel@tonic-gate 		 * UFI devices may not respond to the 0 mode page.
32480Sstevel@tonic-gate 		 * retry with the error recovery page(0x01)
32490Sstevel@tonic-gate 		 */
32500Sstevel@tonic-gate 		if (ucmd.uscsi_status & STATUS_CHECK) {
32510Sstevel@tonic-gate 			cdb[2] = 0x1;	/* page code */
32520Sstevel@tonic-gate 			ret_val = do_uscsi_cmd(fd, &ucmd,
32530Sstevel@tonic-gate 					USCSI_READ|USCSI_RQENABLE);
32540Sstevel@tonic-gate 		}
32550Sstevel@tonic-gate 		if (ret_val || ucmd.uscsi_status) {
32560Sstevel@tonic-gate 			debug(1, "Modesense failed: %d - %d\n",
32570Sstevel@tonic-gate 				ret_val, ucmd.uscsi_status);
32580Sstevel@tonic-gate 			return (-1);
32590Sstevel@tonic-gate 		}
32600Sstevel@tonic-gate 	}
32610Sstevel@tonic-gate 	debug(5, "Modesense succeeded: 0x%x\n", modeh.device_specific);
32620Sstevel@tonic-gate 
32630Sstevel@tonic-gate 	if (modeh.device_specific & 0x80) {
32640Sstevel@tonic-gate 		cur_status = SM_WRITE_PROTECT_NOPASSWD;
32650Sstevel@tonic-gate 	} else {
32660Sstevel@tonic-gate 		cur_status = SM_WRITE_PROTECT_DISABLE;
32670Sstevel@tonic-gate 	}
32680Sstevel@tonic-gate 	return (cur_status);
32690Sstevel@tonic-gate }
3270