1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#include <stdio.h>
28#include <stdio_ext.h>
29#include <errno.h>
30#include <ctype.h>
31#include <syslog.h>
32#include <signal.h>
33#include <limits.h>
34#include <unistd.h>
35#include <sys/types.h>
36#include <sys/mman.h>
37#include <stdlib.h>
38#include <sys/stat.h>
39#include <sys/mkdev.h>
40#include <fcntl.h>
41#include <sys/scsi/scsi.h>
42#include <sys/scsi/generic/commands.h>
43#include <string.h>
44#include <door.h>
45#include <pwd.h>
46#include <thread.h>
47#include <synch.h>
48#include <pthread.h>
49#include <locale.h>
50#include <sys/resource.h>
51#include <netconfig.h>
52#include <sys/smedia.h>
53#include "smserver.h"
54#include <rpc/rpc.h>
55#include "smed.h"
56#include "myaudit.h"
57#include <bsm/libbsm.h>
58#include <bsm/audit_uevents.h>
59#include <utmpx.h>
60
61
62/*
63 * The comments below would help in understanding what is being attempted
64 * in the server.
65 *
66 * The server can be started either by inetd or by the client directly.
67 * Normally the server is started by inetd when the client invokes the
68 * appropriate libsmedia library call(smedia_get_handle).
69 * However since the inetd runs only at init level 2 and above a mechanism
70 * is provided for the server to be started if an attempt is made to use
71 * the libsmedia calls in maintenence mode(init level 1).
72 * The main() routine determines how the server was invoked and takes
73 * the necessary action.
74 * When started by inetd it registers itself as an RPC program.
75 * The server also implements a mechanism by which it removes itself
76 * after a period of inactivity. The period of inactivity is specified
77 * by SVC_CLOSEDOWN which is set at 180 secs.
78 * The logic of detecting inactivity is as follows:
79 *
80 * Two variables svcstate and svccount are used to determine if the server
81 * is IDLE.
82 * The svcstate is set to 1(_SERVED) when ever the server does any operation
83 * on behalf of the client.
84 * The svccount indicates the number of active clients who have established
85 * a connection with the server. A connection is established when the
86 * libsmedia call smedia_get_handle() succeeds.
87 * The connection is broken when the client calls smedia_free_handle() OR
88 * exits.
89 * A thread called closedown is started up when server is started.
90 * This thread runs periodically and monitors both svcstate and svccount.
91 * If svcstate is IDLE and svccount is 0 then server exits.
92 * The svcstate is set to IDLE by the closedown thread. It is set to _SERVED
93 * by server. It is possible for the state to be _SERVED and the svccount
94 * to be 0. The server could be kept busy by client calls of smedia_get_handle
95 * that do not succeed. This is the reason for using both svcstate and svccount
96 * to determine the true server state.
97 *
98 * The communication between client and server is thru door calls.
99 * Below are the door descriptors available to communicate to the server.
100 *
101 * main_door_descriptor:
102 * ---------------------
103 * 	This is a predefined descriptor used by client to establish a
104 * connection with the server. This descriptor is available to the client
105 * as /var/adm/smedia_svc
106 * The client uses the main_door_descriptor to obtain a dedicated
107 * client_door_descriptor for itself. The smedia_get_handle call communicates
108 * to the server using the main_door_descriptor and obtains the
109 * client_door_descriptor which is stored in the handle structure.
110 * All other libsmedia calls use the client_door_descriptor to communicate
111 * with the server.
112 *
113 * client_door_descriptor:
114 * -----------------------
115 *	This is the door descriptor that is used by the clients to
116 * request server to perform the necessary tasks. This door descriptor is
117 * available only to the client for whom it was created.
118 *
119 * death_door_descriptor:
120 * ----------------------
121 * 	The sole function of this descriptor HAD been to inform the server of
122 * the untimely death of the client. This descriptor is no longer used, though
123 * it is still created, as libsmedia expects to use it.  This descriptor's
124 * service procedure had used pthread cancellation(5) to terminate the thread of
125 * the associated client_door_descriptor.  The client_door_descriptor now
126 * handles the scenarios where a door_call/client are aborted/terminated.
127 *
128 * main_servproc()
129 * -------------
130 *	This is the routine associated with the main_door_descriptor.
131 * This is the routine that handles the smedia_get_handle() call
132 * of the client. If the door call to this routine succeeds it creates a
133 * client_door_descriptor that is used by the client in subsequent library
134 * calls.
135 * This client_door_descriptor is passed to the client thru the door_return
136 * call. This client_door_descriptor cannot be used by any other process other
137 * than the client process that obtained it.
138 * In addition to the client_door_descriptor a death_door_descriptor is also
139 * created by the main server and passed on to the client. The client does not
140 * use the death_door_descriptor.
141 *
142 * client_servproc()
143 * ---------------
144 *	This is the routine that handles the libsmedia calls of the
145 * client. In the current implementation the server takes control of the
146 * number of threads that handle the door calls. This is done by creating the
147 * door descriptor as DOOR_PRIVATE.
148 * The server runs only one thread per handle. This makes the implementation
149 * simple as we do not have to use mutex to make the code MT safe.
150 * The server thread has a data structure door_data_t associated with it.
151 *
152 * door_data_t
153 * -----------
154 * This is the data structure that is created by the main_servproc when it
155 * creates the client_door_descriptor. The door mechanism has a way to associate
156 * a cookie with the door descriptor. door_data_t is the cookie for the
157 * client_door_descriptor. This cookie is passed to the server function that
158 * handles the client_door_descriptor calls. In our case it is the
159 * client_servproc routine.
160 * The key elements of the door_data_t are the following:
161 *
162 *	dd_fd		file descriptor for the device.
163 *	dd_buf		The shared memory buffer between client-server.
164 *	dd_thread	The thread that handles the door_calls.
165 *
166 * signal handling:
167 * ----------------
168 *		The main purpose of trapping the signals is to exit gracefully
169 * from the server after recording the appropriate message in the syslog.
170 * This will help the administrator to determine the cause of failure of the
171 * server by examining the log file.
172 *
173 * cleanup()
174 * ---------
175 *	This routine frees up all the resources allocated for the client.
176 * Resources include the file descriptor, shared memory, threads.
177 *
178 * shared memory
179 * -------------
180 *	In order to reduce the overheads of moving large amounts of data
181 * during raw read/write operations, the server uses the mmapped data of
182 * client. The smedia_raw_read, smedia_raw_write library calls mmap the
183 * memory and pass on the file descriptor that maps the memory to the server.
184 * The server subsequently uses this mmapped memory during the IO.
185 * If the mmapped memory changes in size, the server is informed and it
186 * remaps the memory to the changed size.
187 */
188#ifdef DEBUG
189#define	DEFAULT_VERBOSE		1
190#define	DEFAULT_DEBUG		1
191#else
192#define	DEFAULT_VERBOSE		0
193#define	DEFAULT_DEBUG		0
194#endif
195
196#define	N_BADSIGS		(sizeof (badsigs)/sizeof (badsigs[0]))
197#define	MD_LEN			30
198#define	MAXUGNAME		10
199#define	SVC_CLOSEDOWN 		180
200
201/*
202 * We will NOT be permitting the following USCI cmd options.
203 *
204 * RESET of target
205 * RESET of  Bus.
206 * Tagged commands to device
207 * Explicitly setting SYNC/ASYNC mode of operations.
208 * POLLED MODE of operation.
209 * Explicitly setting NO DISCONNECT features.
210 * use of RESERVED flags.
211 */
212#define	FORBIDDEN_FLAGS		(USCSI_RESET | USCSI_RESET_ALL | USCSI_RENEGOT \
213				| USCSI_ASYNC  | USCSI_SYNC | USCSI_NOINTR | \
214				USCSI_NOTAG | USCSI_NOPARITY | USCSI_NODISCON \
215				| USCSI_RESERVED)
216
217/* States a server can be in wrt request */
218
219#define	_IDLE 0
220#define	_SERVED 1
221
222static char		*prog_name;
223static int svcstate = _IDLE;	/* Set when a request is serviced */
224static int svccount = 0;	/* Number of requests being serviced */
225static int svcstart_level = 0;	/* init level when server was started */
226static mutex_t svcstate_lock;	/* lock for svcstate, svccount */
227
228extern	void smserverprog_1(struct svc_req *, SVCXPRT *);
229
230/*
231 * Log messages
232 */
233#define	SIGACT_FAILED	"Failed to install signal handler for %s: %s"
234#define	BADSIG_MSG	"Thread %d Caught signal %d addr=%p trapno=%d pc=%p"
235
236static int	badsigs[] = {SIGSEGV, SIGBUS, SIGFPE, SIGILL};
237
238/* global variables */
239int		verbose		= DEFAULT_VERBOSE;
240int		debug_level	= DEFAULT_DEBUG;
241char		*smediad_devdir = DEFAULT_SMEDIAD_DEVDIR;
242
243thread_key_t	door_key;
244
245server_data_t	server_data;
246
247static int	server_door, server_fd;
248
249static int32_t do_uscsi_cmd(int32_t file, struct uscsi_cmd *uscsi_cmd,
250		int32_t flag);
251static void client_servproc(void *cookie, char *argp, size_t arg_size,
252		door_desc_t *dp, uint_t ndesc);
253static void cleanup(door_data_t *);
254static void *init_server(void *);
255static int32_t scsi_reassign_block(int32_t fd, diskaddr_t);
256static int32_t get_mode_page(int32_t fd, uchar_t pc, uchar_t page_code,
257	uchar_t *md_data, uchar_t data_len);
258static int32_t get_device_type(char *v_name);
259static int32_t get_device_type_scsi(int32_t fd, struct scsi_inquiry *inq);
260
261static int32_t scsi_format(int32_t fd, uint_t flavor, uint_t mode);
262static int32_t scsi_media_status(int32_t fd);
263static int32_t scsi_write_protect(int32_t fd, smwp_state_t *wp);
264static int32_t scsi_floppy_media_status(int32_t fd);
265static int32_t scsi_floppy_write_protect(int32_t fd, smwp_state_t *wp);
266static int32_t scsi_floppy_format(int32_t, uint_t, uint_t);
267static int32_t get_floppy_geom(int32_t fd, uint32_t capacity,
268			struct dk_geom *dkgeom);
269static int32_t get_media_capacity(int32_t fd, uint32_t *capacity,
270			uint32_t *blocksize);
271
272static int32_t scsi_ls120_format(uint_t fd, uint_t flavor, uint32_t capacity,
273			uint32_t blocksize);
274
275static void *sm_server_thread(void *arg);
276static void sm_door_server_create(door_info_t *dip);
277static void term_handler(int sig, siginfo_t *siginfo, void *sigctx);
278static void hup_handler(int sig, siginfo_t *siginfo, void *sigctx);
279static void sig_handler(int sig, siginfo_t *siginfo, void *sigctx);
280static void badsig_handler(int sig, siginfo_t *siginfo, void *sigctx);
281static void server_badsig_handler(int sig, siginfo_t *siginfo, void *sigctx);
282static char *xlate_state(int32_t);
283static uint32_t	get_sector_size(int fd);
284static int32_t raw_read(door_data_t *door_dp, smedia_services_t *req);
285static int32_t raw_write(door_data_t *door_dp, smedia_services_t *req);
286static int32_t reassign_block(door_data_t *door_dp, smedia_services_t *req);
287static int32_t set_protection_status(door_data_t *door_dp,
288			smedia_services_t *req);
289static int32_t set_shfd(door_data_t *door_dp, int32_t fd,
290			smedia_services_t *req);
291
292static void door_ret_err(smedia_reterror_t *reterror, int32_t err);
293static void my_door_return(char *data_ptr, size_t data_size,
294			door_desc_t *desc_ptr, uint_t num_desc);
295static int32_t invalid_uscsi_operation(door_data_t *, struct uscsi_cmd *);
296
297#define	W_E_MASK	0x80
298
299static smserver_info server_info;
300
301static int32_t
302invalid_uscsi_operation(door_data_t *door_dp, struct uscsi_cmd *ucmd)
303{
304
305	if (door_dp->dd_dkinfo.dki_ctype != DKC_CDROM) {
306		debug(5,
307		"Invalid device type(0x%x) found for uscsi cmd.\n",
308			door_dp->dd_dkinfo.dki_ctype);
309		errno = EINVAL;
310		return (EINVAL);
311	}
312	if (ucmd->uscsi_flags & FORBIDDEN_FLAGS) {
313		debug(5,
314		"Invalid flags(0x%x) set in uscsi cmd. cdb[0]=0x%x\n",
315		ucmd->uscsi_flags,  ucmd->uscsi_cdb[0]);
316		errno = EINVAL;
317		return (EINVAL);
318	}
319	if (ucmd->uscsi_cdb[0] == SCMD_COPY ||
320	    ucmd->uscsi_cdb[0] == SCMD_COPY_VERIFY ||
321	    ucmd->uscsi_cdb[0] == SCMD_COMPARE ||
322	    ucmd->uscsi_cdb[0] == SCMD_WRITE_BUFFER) {
323		debug(5,
324		"Invalid command(0x%x) found in cdb.\n",
325		ucmd->uscsi_cdb[0]);
326		errno = EINVAL;
327		return (EINVAL);
328	}
329	return (0);
330}
331
332static uint32_t
333get_sector_size(int fd)
334{
335	uint32_t	sector_size;
336	struct uscsi_cmd	ucmd;
337	union scsi_cdb		cdb;
338	int32_t		ret_val;
339	uint32_t rc_data[2];
340	char rq_data[RQ_LEN];
341
342	cdb.scc_cmd = SCMD_READ_CAPACITY;
343	ucmd.uscsi_cdb = (caddr_t)&cdb;
344	ucmd.uscsi_cdblen = CDB_GROUP1;
345	ucmd.uscsi_bufaddr = (caddr_t)&rc_data;
346	ucmd.uscsi_buflen = sizeof (rc_data);
347	ucmd.uscsi_timeout = 120; /* If 0, HBA hangs forever */
348	ucmd.uscsi_rqlen = RQ_LEN;
349	ucmd.uscsi_rqbuf = rq_data;
350
351	ret_val = do_uscsi_cmd(fd,
352		&ucmd, USCSI_READ|USCSI_RQENABLE);
353	if (ret_val || ucmd.uscsi_status) {
354		debug(5, "Read capacity : %d - %d errno = %d\n",
355			ret_val, ucmd.uscsi_status, errno);
356		sector_size = 512;
357	} else {
358		sector_size = ntohl(rc_data[1]);
359	}
360	debug(5, "sector size = 0x%x(%d)\n",
361		sector_size, sector_size);
362	return (sector_size);
363}
364
365static char *
366xlate_state(int32_t state)
367{
368	switch (state) {
369
370	case SM_WRITE_PROTECT_DISABLE:
371		return ("PROTECTION_DISABLED");
372	case SM_WRITE_PROTECT_PASSWD:
373		return ("WRITE_PROTECT_PASSWD");
374	case SM_WRITE_PROTECT_NOPASSWD:
375		return ("WRITE_PROTECT_NOPASSWD");
376	case SM_READ_WRITE_PROTECT:
377		return ("READ_WRITE_PROTECT");
378	case SM_TEMP_UNLOCK_MODE:
379		return ("PROTECTION DISABLED");
380	default:
381		return ("UNKNOWN_STATE");
382	}
383}
384
385static char *
386xlate_cnum(smedia_callnumber_t cnum)
387{
388	switch (cnum) {
389
390	case SMEDIA_CNUM_OPEN_FD:
391		return ("SMEDIA_CNUM_OPEN_FD");
392	case SMEDIA_CNUM_GET_DEVICE_INFO:
393		return ("SMEDIA_CNUM_GET_DEVICE_INFO");
394	case SMEDIA_CNUM_GET_MEDIUM_PROPERTY:
395		return ("SMEDIA_CNUM_GET_MEDIUM_PROPERTY");
396	case SMEDIA_CNUM_GET_PROTECTION_STATUS:
397		return ("SMEDIA_CNUM_GET_PROTECTION_STATUS");
398	case SMEDIA_CNUM_SET_PROTECTION_STATUS:
399		return ("SMEDIA_CNUM_SET_PROTECTION_STATUS");
400	case SMEDIA_CNUM_RAW_READ:
401		return ("SMEDIA_CNUM_RAW_READ");
402	case SMEDIA_CNUM_RAW_WRITE:
403		return (" SMEDIA_CNUM_RAW_WRITE");
404	case SMEDIA_CNUM_FORMAT:
405		return ("SMEDIA_CNUM_FORMAT");
406	case SMEDIA_CNUM_CHECK_FORMAT_STATUS:
407		return ("SMEDIA_CNUM_CHECK_FORMAT_STATUS");
408	case SMEDIA_CNUM_EJECT:
409		return ("SMEDIA_CNUM_EJECT");
410	case SMEDIA_CNUM_REASSIGN_BLOCK:
411		return ("SMEDIA_CNUM_REASSIGN_BLOCK");
412	case SMEDIA_CNUM_SET_SHFD:
413		return ("SMEDIA_CNUM_SET_SHFD");
414	case SMEDIA_CNUM_PING:
415		return ("SMEDIA_CNUM_PING");
416	case SMEDIA_CNUM_USCSI_CMD:
417		return ("SMEDIA_CNUM_USCSI_CMD");
418	default:
419		return ("UNKNOWN_CNUM");
420	}
421}
422
423/*ARGSUSED*/
424smserver_info *
425smserverproc_get_serverinfo_1(void *argp, CLIENT *clnt)
426{
427	(void) mutex_lock(&svcstate_lock);
428	svcstate = _SERVED;
429	(void) mutex_unlock(&svcstate_lock);
430	server_info.vernum = SMSERVERVERS;
431	server_info.status = 0;
432	(void) mutex_lock(&server_data.sd_init_lock);
433	if (server_data.sd_init_state == INIT_NOT_DONE) {
434		server_data.sd_init_state = INIT_IN_PROGRESS;
435		debug(5, "Initialising server\n");
436		(void) init_server(NULL);
437	}
438	if (server_data.sd_init_state != INIT_DONE) {
439		debug(1, "init_server did not do the job. "
440		    "init_state=%d\n", server_data.sd_init_state);
441		server_data.sd_init_state = INIT_NOT_DONE;
442		(void) mutex_unlock(&server_data.sd_init_lock);
443		server_info.status = -1;
444		return (&server_info);
445	}
446	(void) mutex_unlock(&server_data.sd_init_lock);
447
448	debug(5, "smserverproc thread %d running....\n", pthread_self());
449	return (&server_info);
450}
451
452/*ARGSUSED*/
453static void
454server_badsig_handler(int sig, siginfo_t *siginfo, void *sigctx)
455{
456
457	fatal(gettext(BADSIG_MSG), pthread_self(), sig, siginfo->si_addr,
458		siginfo->si_trapno,
459		siginfo->si_pc);
460}
461
462static int32_t
463do_uscsi_cmd(int32_t file, struct uscsi_cmd *uscsi_cmd, int32_t	flag)
464{
465	int32_t	ret_val;
466
467	/*
468	 * Set function flags for driver.
469	 */
470	uscsi_cmd->uscsi_flags = USCSI_ISOLATE;
471
472#ifdef DEBUG
473	uscsi_cmd->uscsi_flags |= USCSI_DIAGNOSE;
474#else
475	uscsi_cmd->uscsi_flags |= USCSI_SILENT;
476#endif /* DEBUG */
477
478	uscsi_cmd->uscsi_flags |= flag;
479
480	errno = 0;
481	ret_val = ioctl(file, USCSICMD, uscsi_cmd);
482	if (ret_val == 0 && uscsi_cmd->uscsi_status == 0) {
483		return (ret_val);
484	}
485	if (!errno)
486		errno = EIO;
487	return (-1);
488}
489
490static int32_t
491get_device_type(char *v_name)
492{
493	int32_t i;
494
495	for (i = 0; i < 8; i++) {
496		v_name[i] = toupper(v_name[i]);
497	}
498	if (strstr(v_name, "IOMEGA")) {
499		return (SCSI_IOMEGA);
500	}
501	if (strstr(v_name, "FD") ||
502	    strstr(v_name, "LS-120")) {
503		return (SCSI_FLOPPY);
504	}
505	return (SCSI_GENERIC);
506
507}
508
509static int32_t
510get_device_type_scsi(int32_t fd, struct scsi_inquiry *inq)
511{
512	int32_t dev_type;
513	struct uscsi_cmd ucmd;
514	union scsi_cdb  cdb;
515	int32_t	ret_val;
516	char rq_data[RQ_LEN];
517
518	(void) memset((void *) inq, 0, sizeof (struct scsi_inquiry));
519	(void) memset((void *) &ucmd, 0, sizeof (ucmd));
520	(void) memset((void *) &cdb, 0, sizeof (union scsi_cdb));
521	cdb.scc_cmd = SCMD_INQUIRY;
522	FORMG0COUNT(&cdb, sizeof (struct scsi_inquiry));
523	ucmd.uscsi_cdb = (caddr_t)&cdb;
524	ucmd.uscsi_cdblen = CDB_GROUP0;
525	ucmd.uscsi_bufaddr = (caddr_t)inq;
526	ucmd.uscsi_buflen = sizeof (struct scsi_inquiry);
527	ucmd.uscsi_timeout = 120;	/* If 0, HBA hangs forever */
528	ucmd.uscsi_rqlen = RQ_LEN;
529	ucmd.uscsi_rqbuf = rq_data;
530	ret_val = do_uscsi_cmd(fd, &ucmd, USCSI_READ|USCSI_RQENABLE);
531	if (ret_val || ucmd.uscsi_status) {
532		debug(5, "INQUIRY failed: rv = %d  uscsi_status = "
533		    "%d  errno = %d\n", ret_val, ucmd.uscsi_status, errno);
534		return (-1);
535	}
536
537	dev_type = get_device_type(inq->inq_vid);
538
539	debug(5, "dev_type %d\n", dev_type);
540	return (dev_type);
541
542}
543
544static int32_t
545get_media_capacity(int32_t fd, uint32_t *capacity, uint32_t *blocksize)
546{
547	struct uscsi_cmd ucmd;
548	uchar_t cdb[12];
549	int32_t ret_val;
550	uchar_t data[20];
551	char rq_data[RQ_LEN];
552
553	debug(5, "get_media_capacity:\n");
554
555	(void) memset((void *)&data, 0, sizeof (data));
556	(void) memset((void *)&ucmd, 0, sizeof (ucmd));
557	(void) memset((void *)&cdb, 0, sizeof (cdb));
558
559	/* retrieve size discriptor of inserted media */
560	cdb[0] = SCMD_READ_FORMAT_CAP;
561	cdb[8] = 0x14;  /* data size */
562
563	/* Fill in the USCSI fields */
564	ucmd.uscsi_cdb = (caddr_t)&cdb;
565	ucmd.uscsi_cdblen = CDB_GROUP5;
566	ucmd.uscsi_bufaddr = (caddr_t)data;
567	ucmd.uscsi_buflen = sizeof (data);
568	ucmd.uscsi_timeout = 120;
569	ucmd.uscsi_rqlen = RQ_LEN;
570	ucmd.uscsi_rqbuf = rq_data;
571	ret_val = do_uscsi_cmd(fd, &ucmd, USCSI_READ|USCSI_RQENABLE);
572
573	if (ret_val || ucmd.uscsi_status) {
574		debug(5, "Retrieving media info failed: %d - %d\n", ret_val,
575		    ucmd.uscsi_status);
576
577		if ((rq_data[2] == KEY_DATA_PROTECT) && (rq_data[12] == 0x30) &&
578		    (rq_data[13] == 0)) {
579			(void) debug(1, "Invalid command for media\n");
580			errno = EINVAL;
581		}
582		return (-1);
583	}
584
585	/* No media, bail out */
586	if (data[8] == 0x3) {
587		(void) debug(5, "no media in drive\n");
588		return (-1);
589	}
590
591	/*
592	 * Generate capacity and blocksize information
593	 */
594
595	*capacity =  (uint32_t)((data[4] << 24) + (data[5] << 16) +
596	    (data[6] << 8) + data[7]);
597
598	debug(1, "capacity is %x %x %x %x = %x", data[4], data[5], data[6],
599	    data[7], *capacity);
600
601	*blocksize = (uint32_t)((data[9] << 16) + (data[10] << 8) + data[11]);
602
603	return (0);
604}
605
606static int32_t
607scsi_zip_format(int32_t fd, uint_t flavor, uint_t mode)
608{
609	struct uscsi_cmd ucmd;
610	struct scsi_inquiry inq;
611	uchar_t cdb[12];
612	int32_t   ret_val;
613	uchar_t data[4];
614	uint32_t rc_data[2];
615	char rq_data[RQ_LEN];
616	uint32_t capacity;
617
618
619	if ((mode != SM_FORMAT_IMMEDIATE) &&
620		(mode != SM_FORMAT_BLOCKED)) {
621		errno = ENOTSUP;
622		return (ENOTSUP);
623	}
624	/*
625	 * Do an inquiry and try to figure out if it an
626	 * IOMEGA JAZ 2GB device.
627	 */
628
629	(void) memset((void *) &inq, 0, sizeof (inq));
630	(void) memset((void *) &ucmd, 0, sizeof (ucmd));
631	(void) memset((void *) &cdb, 0, sizeof (cdb));
632	(void) memset((void *) &rq_data, 0, sizeof (rq_data));
633	cdb[0] = SCMD_INQUIRY;
634	cdb[4] = sizeof (inq);
635	ucmd.uscsi_cdb = (caddr_t)&cdb;
636	ucmd.uscsi_cdblen = CDB_GROUP0;
637	ucmd.uscsi_bufaddr = (caddr_t)&inq;
638	ucmd.uscsi_buflen = sizeof (inq);
639	ucmd.uscsi_timeout = 120;	/* If 0, HBA hangs forever */
640	ucmd.uscsi_rqlen = RQ_LEN;
641	ucmd.uscsi_rqbuf = rq_data;
642	ret_val = do_uscsi_cmd(fd, &ucmd, USCSI_READ|USCSI_RQENABLE);
643	if (ret_val || ucmd.uscsi_status) {
644		debug(5, "inquiry failed: %d - %d errno = %d\n",
645			ret_val, ucmd.uscsi_status, errno);
646		return (ucmd.uscsi_status);
647	}
648
649	(void) memset((void *) &rc_data, 0, sizeof (rc_data));
650	(void) memset((void *) &ucmd, 0, sizeof (ucmd));
651	(void) memset((void *) &cdb, 0, sizeof (cdb));
652	cdb[0] = SCMD_READ_CAPACITY;
653	ucmd.uscsi_cdb = (caddr_t)&cdb;
654	ucmd.uscsi_cdblen = CDB_GROUP1;
655	ucmd.uscsi_bufaddr = (caddr_t)&rc_data;
656	ucmd.uscsi_buflen = sizeof (rc_data);
657	ucmd.uscsi_timeout = 120;	/* If 0, HBA hangs forever */
658
659	ret_val = do_uscsi_cmd(fd, &ucmd, USCSI_READ);
660	if (ret_val || ucmd.uscsi_status) {
661		debug(5, "Read capacity : %d - %d errno = %d\n",
662			ret_val, ucmd.uscsi_status, errno);
663		return (ucmd.uscsi_status);
664	}
665
666	capacity = ntohl(rc_data[0]);
667
668	(void) memset((void *)&data, 0, sizeof (data));
669	(void) memset((void *)&ucmd, 0, sizeof (ucmd));
670	(void) memset((void *)&cdb, 0, sizeof (cdb));
671	cdb[0] =  SCMD_FORMAT;
672	/*
673	 * Defect list sent by initiator is a complete list of defects.
674	 */
675	cdb[1] = (FMTDATA | CMPLIST);
676	/*
677	 * Target should examine the setting of the DPRY, DCRT, STPF, IP
678	 * and DSP bits.
679	 */
680	data[1] = FOV;
681
682	switch (flavor) {
683		case SM_FORMAT_QUICK :
684			/*
685			 * Target should not perform any vendor specific
686			 * medium certification process or format verification
687			 */
688			data[1] = (FOV | DCRT);
689			/*
690			 * Defect list sent is an addition to the existing
691			 * list of defects.
692			 */
693			cdb[1] =  FMTDATA;
694			break;
695		case SM_FORMAT_FORCE :
696			if (strstr(inq.inq_pid, "jaz")) {
697				debug(1,
698				"LONG Format of JAZ media not supported\n");
699				errno = ENOTSUP;
700				return (ENOTSUP);
701			}
702			/*
703			 * Formatting a write-protected or read/write
704			 * protected cartridge is allowed.
705			 * This is a vendor specific Format Option.
706			 */
707			cdb[2] = 0x20;
708			break;
709		case SM_FORMAT_LONG :
710			if (strstr(inq.inq_pid, "jaz")) {
711				debug(1,
712				"LONG Format of JAZ media not supported\n");
713				errno = ENOTSUP;
714				return (ENOTSUP);
715			}
716			/*
717			 * Defect list sent is an addition to the existing
718			 * list of defects.
719			 */
720			cdb[1] = FMTDATA;
721			break;
722		default :
723			debug(1, "Format option %d not supported!!\n",
724			flavor);
725			errno = ENOTSUP;
726			return (ENOTSUP);
727	}
728
729	if (mode == SM_FORMAT_IMMEDIATE) {
730		data[1] |= IMMED;
731		debug(5, "immediate_flag set\n");
732	}
733
734	ucmd.uscsi_cdb = (caddr_t)&cdb;
735	debug(5, "cdb: %x ", cdb[0]);
736	debug(5, "%x %x ", cdb[1], cdb[2]);
737	debug(5, "%x %x %x\n", cdb[3], cdb[4], cdb[5]);
738	debug(5, "data: %x %x %x %x\n", data[0], data[1], data[2], data[3]);
739
740	ucmd.uscsi_cdblen = CDB_GROUP0;
741	ucmd.uscsi_bufaddr = (caddr_t)data;
742	ucmd.uscsi_buflen = sizeof (data);
743	ucmd.uscsi_timeout = FORMAT_TIMEOUT(capacity);
744	ucmd.uscsi_rqlen = RQ_LEN;
745	ucmd.uscsi_rqbuf = rq_data;
746	ret_val = do_uscsi_cmd(fd, &ucmd, USCSI_WRITE|USCSI_RQENABLE);
747	if (ret_val || ucmd.uscsi_status) {
748		debug(5, "Format failed : %d - uscsi_status = %d errno = %d\n",
749			ret_val,
750			ucmd.uscsi_status, errno);
751		if ((rq_data[2] == KEY_DATA_PROTECT) ||
752			(rq_data[2] == KEY_ILLEGAL_REQUEST))
753			errno = EINVAL;
754		if ((rq_data[2] == KEY_MEDIUM_ERROR) ||
755			(rq_data[2] == KEY_HARDWARE_ERROR))
756			errno = EIO;
757		return (errno);
758	}
759
760	return (0);
761}
762
763static int32_t
764scsi_ls120_format(uint_t fd, uint_t flavor, uint32_t capacity,
765    uint32_t blocksize)
766{
767	struct uscsi_cmd ucmd;
768	uchar_t cdb[12];
769	int32_t ret_val;
770	uchar_t data[12];
771	char	rq_data[RQ_LEN];
772
773	debug(5, "scsi_ls120_format:\n");
774
775	(void) memset((void *) &ucmd, 0, sizeof (ucmd));
776	(void) memset((void *) &cdb, 0, sizeof (cdb));
777	(void) memset((void *) &rq_data, 0, sizeof (rq_data));
778
779	cdb[0] = SCMD_FORMAT;
780	cdb[1] = (FMTDATA | 0x7);
781	cdb[8] = 0x0C; /* parameter list length */
782
783	data[1] = 0x80;
784	data[3] = 0x08;
785
786
787	data[4] = (capacity >> 24) & 0xff;
788	data[5] = (capacity >> 16) & 0xff;
789	data[6] = (capacity >> 8) & 0xff;
790	data[7] = capacity & 0xff;
791
792
793	data[9] =  (blocksize >> 16) & 0xff;
794	data[10] = (blocksize >> 8) & 0xff;
795	data[11] = blocksize & 0xff;
796
797	debug(5, "cdb: %x %x %x ... %x", cdb[0], cdb[1], cdb[2], cdb[8]);
798	debug(5, "data: %x %x %x %x\n", data[0], data[1], data[2], data[3]);
799	debug(5, "    : %x %x %x %x\n", data[4], data[5], data[6], data[7]);
800	debug(5, "    : %x %x %x %x\n", data[8], data[9], data[10], data[11]);
801
802	switch (flavor) {
803		case SM_FORMAT_QUICK :
804			debug(1, "Format not supported\n");
805			errno = ENOTSUP;
806			return (-1);
807		case SM_FORMAT_FORCE :
808			break;
809		case SM_FORMAT_LONG :
810			break;
811		default :
812			debug(1, "Format option not specified!!\n");
813			errno = ENOTSUP;
814			return (-1);
815	}
816
817	ucmd.uscsi_cdb = (caddr_t)&cdb;
818
819
820	ucmd.uscsi_cdblen = CDB_GROUP5;
821	ucmd.uscsi_bufaddr = (caddr_t)data;
822	ucmd.uscsi_buflen = sizeof (data);
823	ucmd.uscsi_timeout = 0x12c0;
824	ucmd.uscsi_rqlen = RQ_LEN;
825	ucmd.uscsi_rqbuf = rq_data;
826	(void) fflush(stdout);
827
828	ret_val = do_uscsi_cmd(fd, &ucmd, USCSI_WRITE|USCSI_RQENABLE);
829	if (ret_val || ucmd.uscsi_status) {
830		debug(1, "Format failed failed: %d - %d\n", ret_val,
831		    ucmd.uscsi_status);
832
833		if ((rq_data[2] == KEY_DATA_PROTECT) &&
834		    (rq_data[12] == 0x30) && (rq_data[13] == 0)) {
835
836			debug(1, "Invalid command for media\n");
837			errno = EINVAL;
838		}
839
840		if ((rq_data[2] == KEY_NOT_READY) && (rq_data[12] == 0x30)) {
841			debug(1, "Incompatible media.\n");
842			errno = EINVAL;
843		}
844
845		return (-1);
846	}
847
848	return (0);
849}
850
851static int32_t
852scsi_format(int32_t fd, uint_t flavor, uint_t mode)
853{
854	struct uscsi_cmd ucmd;
855	struct scsi_inquiry inq;
856	uchar_t cdb[12];
857	int32_t   ret_val;
858	uchar_t data[4];
859	char rq_data[RQ_LEN];
860	uint32_t rc_data[2];
861	uint32_t capacity;
862
863
864
865	if ((mode != SM_FORMAT_IMMEDIATE) &&
866		(mode != SM_FORMAT_BLOCKED)) {
867		errno = ENOTSUP;
868		return (-1);
869	}
870
871	/*
872	 * Do an inquiry and try to figure out if it an
873	 * IOMEGA JAZ 2GB device.
874	 */
875
876	(void) memset((void *) &inq, 0, sizeof (inq));
877	(void) memset((void *) &ucmd, 0, sizeof (ucmd));
878	(void) memset((void *) &cdb, 0, sizeof (cdb));
879	(void) memset((void *) &rq_data, 0, sizeof (rq_data));
880	cdb[0] = SCMD_INQUIRY;
881	cdb[4] = sizeof (inq);
882	ucmd.uscsi_cdb = (caddr_t)&cdb;
883	ucmd.uscsi_cdblen = CDB_GROUP0;
884	ucmd.uscsi_bufaddr = (caddr_t)&inq;
885	ucmd.uscsi_buflen = sizeof (inq);
886	ucmd.uscsi_timeout = 120;	/* If 0, HBA hangs forever */
887	ucmd.uscsi_rqlen = RQ_LEN;
888	ucmd.uscsi_rqbuf = rq_data;
889	ret_val = do_uscsi_cmd(fd, &ucmd, USCSI_READ|USCSI_RQENABLE);
890	if (ret_val || ucmd.uscsi_status) {
891		debug(5, "inquiry failed: %d - %d errno = %d\n",
892			ret_val, ucmd.uscsi_status, errno);
893		return (ucmd.uscsi_status);
894	}
895
896	(void) memset((void *) &rc_data, 0, sizeof (rc_data));
897	(void) memset((void *) &ucmd, 0, sizeof (ucmd));
898	(void) memset((void *) &cdb, 0, sizeof (cdb));
899	cdb[0] = SCMD_READ_CAPACITY;
900	ucmd.uscsi_cdb = (caddr_t)&cdb;
901	ucmd.uscsi_cdblen = CDB_GROUP1;
902	ucmd.uscsi_bufaddr = (caddr_t)&rc_data;
903	ucmd.uscsi_buflen = sizeof (rc_data);
904	ucmd.uscsi_timeout = 120;	/* If 0, HBA hangs forever */
905
906	ret_val = do_uscsi_cmd(fd, &ucmd, USCSI_READ);
907	if (ret_val || ucmd.uscsi_status) {
908		debug(5, "Read capacity : %d - %d errno = %d\n",
909			ret_val, ucmd.uscsi_status, errno);
910		return (ucmd.uscsi_status);
911	}
912
913	capacity = ntohl(rc_data[0]);
914
915	(void) memset((void *)&data, 0, sizeof (data));
916	(void) memset((void *)&ucmd, 0, sizeof (ucmd));
917	(void) memset((void *)&cdb, 0, sizeof (cdb));
918	cdb[0] =  SCMD_FORMAT;
919	/*
920	 * Defect list sent is an addition to the existing
921	 * list of defects.
922	 */
923	cdb[1] =  FMTDATA;
924	/*
925	 * Target should examine the setting of the DPRY, DCRT, STPF, IP
926	 * and DSP bits.
927	 */
928	data[1] = FOV;
929
930	if (mode == SM_FORMAT_IMMEDIATE) {
931		debug(5,
932	"SM_FORMAT_IMMEDIATE specified ignored. Performing a long format!\n");
933	}
934
935	switch (flavor) {
936		case SM_FORMAT_LONG :
937			if (strstr(inq.inq_pid, "jaz")) {
938				debug(1,
939				"LONG Format of JAZ media not supported\n");
940				errno = ENOTSUP;
941				return (ENOTSUP);
942			}
943			/*
944			 * Defect list sent is an addition to the existing
945			 * list of defects.
946			 */
947			cdb[1] = FMTDATA;
948			break;
949		default :
950			debug(1, "Format option %d  not supported!!\n",
951			flavor);
952			errno = ENOTSUP;
953			return (ENOTSUP);
954	}
955
956
957	ucmd.uscsi_cdb = (caddr_t)&cdb;
958	ucmd.uscsi_cdblen = CDB_GROUP0;
959	ucmd.uscsi_bufaddr = (caddr_t)data;
960	ucmd.uscsi_buflen = sizeof (data);
961	ucmd.uscsi_timeout = FORMAT_TIMEOUT(capacity);
962	ucmd.uscsi_rqlen = RQ_LEN;
963	ucmd.uscsi_rqbuf = rq_data;
964	ret_val = do_uscsi_cmd(fd, &ucmd, USCSI_WRITE|USCSI_RQENABLE);
965	if (ret_val || ucmd.uscsi_status) {
966		debug(5, "Format failed failed: %d - %d errno = %d\n",
967			ret_val, ucmd.uscsi_status, errno);
968		return (ucmd.uscsi_status);
969	}
970
971	return (0);
972}
973
974static int32_t
975scsi_media_status(int32_t fd)
976{
977	struct mode_header modeh;
978	struct uscsi_cmd ucmd;
979	union scsi_cdb  cdb;
980	int32_t ret_val;
981	int32_t cur_status;
982	char rq_data[RQ_LEN];
983
984	debug(10, "SCSI MEDIA STATUS CALLED \n");
985
986	(void) memset((void *) &modeh, 0, sizeof (modeh));
987	(void) memset((void *) &ucmd, 0, sizeof (ucmd));
988	(void) memset((void *) &cdb, 0, sizeof (union scsi_cdb));
989	cdb.scc_cmd = SCMD_MODE_SENSE;
990	cdb.cdb_opaque[2] = MODEPAGE_ALLPAGES;
991	FORMG0COUNT(&cdb, sizeof (modeh));
992
993	ucmd.uscsi_cdb = (caddr_t)&cdb;
994	ucmd.uscsi_cdblen = CDB_GROUP0;
995	ucmd.uscsi_bufaddr = (caddr_t)&modeh;
996	ucmd.uscsi_buflen = sizeof (modeh);
997	ucmd.uscsi_timeout = 120;	/* If 0, HBA hangs forever */
998	ucmd.uscsi_rqlen = RQ_LEN;
999	ucmd.uscsi_rqbuf = rq_data;
1000	ret_val = do_uscsi_cmd(fd, &ucmd, USCSI_READ|USCSI_RQENABLE);
1001	if (ret_val || ucmd.uscsi_status) {
1002		debug(5, "Modesense for 0x3f pages failed: %d-%d errno=%d\n",
1003			ret_val, ucmd.uscsi_status, errno);
1004		cdb.cdb_opaque[2] = 0;
1005		ucmd.uscsi_rqlen = RQ_LEN;
1006		FORMG0COUNT(&cdb, sizeof (modeh));
1007		ret_val = do_uscsi_cmd(fd, &ucmd, USCSI_READ|USCSI_RQENABLE);
1008		if (ret_val || ucmd.uscsi_status) {
1009			debug(5, "Modesense failed: %d - %d errno = %d\n",
1010				ret_val, ucmd.uscsi_status, errno);
1011			return (-1);
1012		}
1013	}
1014
1015	if (modeh.device_specific & W_E_MASK) {
1016		cur_status = SM_WRITE_PROTECT_NOPASSWD;
1017	} else {
1018		cur_status = SM_WRITE_PROTECT_DISABLE;
1019	}
1020	debug(5, "cur status %d\n", cur_status);
1021
1022	return (cur_status);
1023}
1024
1025static int32_t
1026scsi_zip_media_status(int32_t fd)
1027{
1028	struct uscsi_cmd ucmd;
1029	uchar_t cdb[12];
1030	int32_t	status;
1031	int32_t mode;
1032	uchar_t data[64];
1033	char rq_data[RQ_LEN];
1034
1035	debug(10, "Getting media status\n");
1036
1037	(void) memset((void *)&ucmd, 0, sizeof (ucmd));
1038	(void) memset((void *)&cdb, 0, sizeof (cdb));
1039
1040	cdb[0] = IOMEGA_NONSENSE_CMD;
1041	cdb[2] = CARTRIDGE_STATUS_PAGE;
1042	cdb[4] = ND_LENGTH;
1043	ucmd.uscsi_cdb = (caddr_t)&cdb;
1044	ucmd.uscsi_cdblen = CDB_GROUP0;
1045	ucmd.uscsi_bufaddr = (caddr_t)data;
1046	ucmd.uscsi_buflen = 64;
1047	ucmd.uscsi_timeout = 120;	/* If 0, HBA hangs forever */
1048	ucmd.uscsi_rqlen = RQ_LEN;
1049	ucmd.uscsi_rqbuf = rq_data;
1050	status = do_uscsi_cmd(fd, &ucmd, USCSI_READ|USCSI_RQENABLE);
1051	if (status || ucmd.uscsi_status) {
1052		debug(5, "Cartridge protect operation failed: "
1053		    "rv = %d  uscsi_status = %d  errno = %d\n",
1054		    status, ucmd.uscsi_status, errno);
1055		return (-1);
1056	}
1057
1058	if (data[DISK_STATUS_OFFSET + NON_SENSE_HDR_LEN] == 4) {
1059		debug(1, "Disk not present. \n");
1060		return (-1);
1061	}
1062	mode = data[PROTECT_MODE_OFFSET + NON_SENSE_HDR_LEN] & 0xF;
1063
1064	debug(5, "MODE 0x%x / %d.\n", mode, mode);
1065
1066	switch (mode) {
1067		case UNLOCK_MODE:
1068			status = SM_WRITE_PROTECT_DISABLE;
1069			break;
1070		case WRITE_PROTECT_MODE:
1071			status = SM_WRITE_PROTECT_NOPASSWD;
1072			break;
1073		case PASSWD_WRITE_PROTECT_MODE:
1074			status = SM_WRITE_PROTECT_PASSWD;
1075			break;
1076		case READ_WRITE_PROTECT_MODE:
1077			status = SM_READ_WRITE_PROTECT;
1078			break;
1079		default :
1080			if (mode & TEMP_UNLOCK_MODE)
1081				status = SM_TEMP_UNLOCK_MODE;
1082			else
1083				status = SM_STATUS_UNKNOWN;
1084			break;
1085	}
1086
1087	debug(5, "status %d \n", status);
1088	return (status);
1089}
1090
1091static int32_t
1092scsi_reassign_block(int32_t fd, diskaddr_t block)
1093{
1094	uchar_t data[8];
1095	struct uscsi_cmd ucmd;
1096	char cdb[12];
1097	int32_t	ret_val;
1098	char rq_data[RQ_LEN];
1099
1100	debug(5, "SCSI REASSIGN CALLED block = %lld\n", block);
1101
1102	(void) memset((void *) &data, 0, sizeof (data));
1103	(void) memset((void *) &ucmd, 0, sizeof (ucmd));
1104	(void) memset((void *) &cdb, 0, sizeof (cdb));
1105	cdb[0] = SCMD_REASSIGN_BLOCK;
1106	data[3] = 4;
1107	data[4] = ((block & 0xFF000000) >> 24);
1108	data[5] = ((block & 0xFF0000) >> 16);
1109	data[6] = ((block & 0xFF00) >> 8);
1110	data[7] = block & 0xFF;
1111
1112	ucmd.uscsi_cdb = (caddr_t)&cdb;
1113	ucmd.uscsi_cdblen = CDB_GROUP0;
1114	ucmd.uscsi_bufaddr = (caddr_t)data;
1115	ucmd.uscsi_buflen = sizeof (data);
1116	ucmd.uscsi_timeout = 120;	/* If 0, HBA hangs forever */
1117	ucmd.uscsi_rqlen = RQ_LEN;
1118	ucmd.uscsi_rqbuf = rq_data;
1119	ret_val = do_uscsi_cmd(fd, &ucmd, USCSI_WRITE|USCSI_RQENABLE);
1120	if (ret_val || ucmd.uscsi_status) {
1121		debug(5, "Reassign block failed: %d - %d errno = %d\n",
1122			ret_val, ucmd.uscsi_status, errno);
1123		return (-1);
1124	}
1125
1126	return (0);
1127}
1128
1129static int32_t
1130get_mode_page(int32_t fd, uchar_t pc, uchar_t page_code,
1131    uchar_t *md_data, uchar_t data_len)
1132{
1133	struct uscsi_cmd ucmd;
1134	uchar_t cdb[12];
1135	int32_t	ret_val;
1136	char rq_data[RQ_LEN];
1137
1138	debug(10, "MODE SENSE(6) - page_code = 0x%x\n", page_code);
1139
1140	(void) memset((void *) md_data, 0, sizeof (data_len));
1141	(void) memset((void *) &ucmd, 0, sizeof (ucmd));
1142	(void) memset((void *) &cdb, 0, sizeof (cdb));
1143	cdb[0] = SCMD_MODE_SENSE;
1144	cdb[2] = (pc << 6) | page_code;
1145	cdb[4] = data_len;
1146
1147	ucmd.uscsi_cdb = (caddr_t)&cdb;
1148	ucmd.uscsi_cdblen = CDB_GROUP0;
1149	ucmd.uscsi_bufaddr = (caddr_t)md_data;
1150	ucmd.uscsi_buflen = data_len;
1151	ucmd.uscsi_timeout = 120;	/* If 0, HBA hangs forever */
1152	ucmd.uscsi_rqlen = RQ_LEN;
1153	ucmd.uscsi_rqbuf = rq_data;
1154	ret_val = do_uscsi_cmd(fd, &ucmd, USCSI_READ|USCSI_RQENABLE);
1155	if (ret_val || ucmd.uscsi_status) {
1156		debug(5, "Modesense failed: %d - %d errno = %d\n",
1157			ret_val, ucmd.uscsi_status, errno);
1158		return (-2);
1159	}
1160
1161	return (0);
1162}
1163
1164static int32_t
1165scsi_zip_write_protect(int32_t fd, smwp_state_t *wp)
1166{
1167	struct uscsi_cmd ucmd;
1168	struct scsi_inquiry inq;
1169	uchar_t cdb[12];
1170	int32_t	status;
1171	int32_t new_mode;
1172	char rq_data[RQ_LEN];
1173	int32_t wa_bit;
1174	char *tmp_passwd = NULL;
1175
1176	debug(10, "SCSI ZIP WRITE PROTECT CALLED \n");
1177
1178	/*
1179	 * Do an inquiry and try to figure out if it an
1180	 * ATAPI or SCSI device.
1181	 */
1182
1183	(void) memset((void *) &inq, 0, sizeof (inq));
1184	(void) memset((void *) &ucmd, 0, sizeof (ucmd));
1185	(void) memset((void *) &cdb, 0, sizeof (cdb));
1186	(void) memset((void *) &rq_data, 0, sizeof (rq_data));
1187	cdb[0] = SCMD_INQUIRY;
1188	cdb[4] = sizeof (inq);
1189	ucmd.uscsi_cdb = (caddr_t)&cdb;
1190	ucmd.uscsi_cdblen = CDB_GROUP0;
1191	ucmd.uscsi_bufaddr = (caddr_t)&inq;
1192	ucmd.uscsi_buflen = sizeof (inq);
1193	ucmd.uscsi_timeout = 120;	/* If 0, HBA hangs forever */
1194	ucmd.uscsi_rqlen = RQ_LEN;
1195	ucmd.uscsi_rqbuf = rq_data;
1196	status = do_uscsi_cmd(fd, &ucmd, USCSI_READ|USCSI_RQENABLE);
1197	if (status || ucmd.uscsi_status) {
1198		debug(5, "inquiry failed: %d - %d errno = %d\n",
1199			status, ucmd.uscsi_status, errno);
1200		return (-1);
1201	}
1202
1203	if (inq.inq_ansi > 0) {
1204		wa_bit = 0;
1205		debug(5, "SCSI device\n");
1206	} else {
1207		wa_bit = 1;
1208		debug(5, "ATAPI device\n");
1209	}
1210
1211	switch (wp->sm_new_state) {
1212		case SM_WRITE_PROTECT_DISABLE :
1213			new_mode = 0x0;
1214			break;
1215		case SM_WRITE_PROTECT_NOPASSWD :
1216			new_mode = 0x2;
1217			break;
1218		case SM_WRITE_PROTECT_PASSWD :
1219			new_mode = 0x3;
1220			break;
1221		case SM_READ_WRITE_PROTECT :
1222			new_mode = 0x5;
1223			break;
1224		case SM_TEMP_UNLOCK_MODE :
1225			new_mode = 0x8;
1226			break;
1227		default :
1228			debug(1, "Invalid mode 0x%x specified\n",
1229			wp->sm_new_state);
1230			errno = ENOTSUP;
1231			return (-1);
1232	}
1233
1234
1235	(void) memset((void *)&ucmd, 0, sizeof (ucmd));
1236	(void) memset((void *)&cdb, 0, sizeof (cdb));
1237	(void) memset((void *) &rq_data, 0, sizeof (rq_data));
1238	cdb[0] = IOMEGA_CATRIDGE_PROTECT;
1239	cdb[1] |= new_mode;
1240	if (wa_bit)
1241		cdb[1] |= WA_BIT;
1242	cdb[4] = wp->sm_passwd_len;
1243	ucmd.uscsi_cdb = (caddr_t)&cdb;
1244	ucmd.uscsi_cdblen = CDB_GROUP0;
1245	if (wa_bit && (wp->sm_passwd_len & 1)) {
1246		/*
1247		 * Oops, ATAPI device with an odd length passwd!
1248		 * Allocate a buffer to hold one extra byte.
1249		 */
1250		debug(5, "Odd len passwd for ATAPI device!\n");
1251		errno = 0;
1252		tmp_passwd = (char *)malloc(wp->sm_passwd_len+1);
1253		if (tmp_passwd == NULL) {
1254			if (errno == 0)
1255				errno = ENOMEM;
1256			return (-1);
1257		}
1258		(void) memset(tmp_passwd, 0, wp->sm_passwd_len+1);
1259		(void) memcpy(tmp_passwd, wp->sm_passwd, wp->sm_passwd_len);
1260		ucmd.uscsi_bufaddr = (caddr_t)tmp_passwd;
1261		ucmd.uscsi_buflen = wp->sm_passwd_len+1;
1262	} else {
1263		ucmd.uscsi_bufaddr = (caddr_t)wp->sm_passwd;
1264		ucmd.uscsi_buflen = wp->sm_passwd_len;
1265	}
1266	ucmd.uscsi_timeout = 120;	/* If 0, HBA hangs forever */
1267	ucmd.uscsi_rqlen = RQ_LEN;
1268	ucmd.uscsi_rqbuf = rq_data;
1269	status = do_uscsi_cmd(fd, &ucmd, USCSI_WRITE|USCSI_RQENABLE);
1270	if (tmp_passwd != NULL) {
1271		free(tmp_passwd);
1272	}
1273	if (status || ucmd.uscsi_status) {
1274		debug(5, "Cartridge-protect operation failed: rv "
1275		    "= %d  uscsi_status = %d  errno = %d\n", status,
1276		    ucmd.uscsi_status, errno);
1277		if ((rq_data[2] & 0xF) == KEY_ILLEGAL_REQUEST) {
1278			if (rq_data[12] == 0x26) {
1279				/* Wrong passwd */
1280				debug(5, "Protection Request with wrong "
1281				    "passwd. errno is being set to EACCES.\n");
1282				errno = EACCES;
1283			}
1284		}
1285		return (-1);
1286	}
1287
1288	return (0);
1289}
1290
1291/*ARGSUSED*/
1292static int32_t
1293scsi_write_protect(int32_t fd, smwp_state_t *wp)
1294{
1295	errno = ENOTSUP;
1296	return (-1);
1297}
1298
1299/*
1300 * This thread becomes the server-side thread used in
1301 * the implementation of a door_call between a client
1302 * and the Client Door.
1303 *
1304 * This thread is customized both by the door_server_create(3c)
1305 * function sm_door_server_create, as well as by itself.
1306 *
1307 * This thread needs to synchronize with the
1308 * main_servproc[SMEDIA_CNUM_OPEN_FD] door_call in terms of
1309 * both successful and failure scenarios.  main_servproc
1310 * locks dd_lock before calling door_create.  This thread
1311 * then attempts to lock, but will block until main_servproc
1312 * has either created all doors it requires, or until a
1313 * door_create has failed (door_create's return and the
1314 * creation of an associated thread are asynchronous).
1315 *
1316 * If door_create failed, this thread will be able to obtain
1317 * dd_lock and call pthread_exit.  If all door_create's succeed,
1318 * this thread will obtain dd_lock and commence with
1319 * customizing the thread's attributes.  door_bind is called to
1320 * bind this thread to the per-door private thread pool, and
1321 * main_servproc is cond_signal'd to avail it of this fact.
1322 *
1323 * Finally, this thread calls door_return, which causes it to
1324 * commence its lifetime as a server-side thread in implementation
1325 * of a Client Door door_call.
1326 */
1327static void *
1328sm_server_thread(void *arg)
1329{
1330	door_data_t	*door_dp;
1331	struct		sigaction act;
1332	int		i;
1333	int		err;
1334
1335	door_dp = (door_data_t *)arg;
1336
1337	if (door_dp == NULL) {
1338		fatal("sm_server_thread[%d]: argument is NULL!!\n",
1339		    pthread_self());
1340		exit(-1);
1341	}
1342
1343	/* Wait for Client Door to be created */
1344	(void) mutex_lock(&door_dp->dd_lock);
1345	if (door_dp->dd_cdoor_descriptor < 0) {
1346		debug(5, "sm_server_thread[%d]: door_create() failed",
1347		    pthread_self());
1348		(void) mutex_unlock(&door_dp->dd_lock);
1349		pthread_exit((void *)-2);
1350	}
1351	(void) mutex_unlock(&door_dp->dd_lock);
1352
1353	for (i = 0; i < N_BADSIGS; i++) {
1354		act.sa_sigaction = server_badsig_handler;
1355		(void) sigemptyset(&act.sa_mask);
1356		act.sa_flags = SA_SIGINFO;
1357		if (sigaction(badsigs[i], &act, NULL) == -1)
1358			warning(gettext(SIGACT_FAILED), strsignal(badsigs[i]),
1359			    strerror(errno));
1360	}
1361	if (sigemptyset(&door_dp->dd_newset) != 0)
1362		warning(gettext("sigemptyset failed. errno = %d\n"),
1363		    errno);
1364	if ((err = pthread_sigmask(SIG_BLOCK, &door_dp->dd_newset, NULL)) != 0)
1365		warning(gettext("pthread_sigmask failed = %d\n"), err);
1366
1367	/* Bind thread with pool associated with Client Door */
1368
1369	if (door_bind(door_dp->dd_cdoor_descriptor) < 0) {
1370		fatal("door_bind");
1371		exit(-1);
1372	}
1373	debug(5, "thr[%d] bound to Client Door[%d]", pthread_self(),
1374	    door_dp->dd_cdoor_descriptor);
1375
1376	/*
1377	 * Set these two cancellation(5) attributes.  Ensure that the
1378	 * pthread we create has cancellation(5) DISABLED and DEFERRED,
1379	 * as our implementation is based on this.  DEFERRED is the
1380	 * default, but set it anyways, in case the defaults change in
1381	 * the future.
1382	 */
1383	if ((err = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL)) != 0)
1384		warning(gettext("pthread_setcancelstate(PTHREAD_CANCEL_DISABLE)"
1385		    " failed = %d\n"), err);
1386	if ((err = pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED,
1387	    NULL)) != 0)
1388		warning(gettext("pthread_setcanceltype(DEFERRED) "
1389		    "failed = %d\n"), err);
1390
1391	/* Inform main_servproc that door_bind() is complete. */
1392	(void) cond_signal(&door_dp->dd_cv_bind);
1393
1394	/*
1395	 * Per doors protocol, transfer control to the doors-runtime in
1396	 * order to make this thread available to answer future door_call()'s.
1397	 */
1398	(void) door_return(NULL, 0, NULL, 0);
1399	return (NULL);
1400}
1401
1402/*
1403 * This function cleans up all per-connection resources.
1404 *
1405 * This function is called when the Client Door's service procedure
1406 * (client_servproc) is called w/ DOOR_UNREF_DATA, which is the
1407 * doors protocol convention stating that the number of file
1408 * descriptors referring to this door has dropped to one.
1409 * client_servproc is passed DOOR_UNREF_DATA because the Client Door
1410 * was door_create'd with the DOOR_UNREF bitflag.
1411 */
1412static void
1413cleanup(door_data_t *door_dp)
1414{
1415	/* do door_revoke() of Death Door */
1416	if (door_dp->dd_ddoor_descriptor >= 0) {
1417		debug(1, "cleanup[%d]: door_revoke() Death Door[%d]",
1418		    pthread_self(), door_dp->dd_ddoor_descriptor);
1419
1420		if (door_revoke(door_dp->dd_ddoor_descriptor) < 0) {
1421			warning(gettext("cleanup[%d]: door_revoke() of Death "
1422			    "Door(%d) failed = %d"), pthread_self(),
1423			    door_dp->dd_ddoor_descriptor, errno);
1424		} else {
1425			door_dp->dd_ddoor_descriptor = -1;
1426		}
1427	}
1428
1429	/* release memory that is shared between client and (our) server */
1430	if (door_dp->dd_buffd >= 0) {
1431		debug(1, "cleanup[%d]: release shared memory", pthread_self());
1432		(void) munmap(door_dp->dd_buf, door_dp->dd_buf_len);
1433		(void) close(door_dp->dd_buffd);
1434
1435		door_dp->dd_buffd = -1;
1436		door_dp->dd_buf = NULL;
1437		door_dp->dd_buf_len = 0;
1438	}
1439
1440	/* close the (target) device that the Client is operating on */
1441	if (door_dp->dd_fd >= 0) {
1442		debug(1, "cleanup[%d]: close(%d) target device", pthread_self(),
1443		    door_dp->dd_fd);
1444		if (close(door_dp->dd_fd) < 0) {
1445			warning(gettext("cleanup[%d]: close() of target device"
1446			    "failed = %d\n"), pthread_self(), errno);
1447		}
1448	}
1449
1450	/*
1451	 * Unbind the current thread from the Client Door's private
1452	 * thread pool.
1453	 */
1454	debug(1, "cleanup[%d]: door_unbind() of Client Door[%d]",
1455	    pthread_self(), door_dp->dd_cdoor_descriptor);
1456	if (door_unbind() < 0)
1457		warning("door_unbind() of Client Door[%d] failed = "
1458		    "%d", door_dp->dd_cdoor_descriptor, errno);
1459
1460	/* Disallow any future requests to the Client Door */
1461	if (door_dp->dd_cdoor_descriptor >= 0) {
1462		debug(1, "cleanup[%d]: door_revoke() Client Door[%d]",
1463		    pthread_self(), door_dp->dd_cdoor_descriptor);
1464
1465		if (door_revoke(door_dp->dd_cdoor_descriptor) < 0) {
1466			warning(gettext("cleanup[%d]: door_revoke() of "
1467			    "Client Door[%d] failed = %d"), pthread_self(),
1468			    door_dp->dd_cdoor_descriptor, errno);
1469		}
1470	}
1471
1472	free(door_dp);
1473	debug(5, "cleanup[%d] ...exiting\n", pthread_self());
1474}
1475
1476/*
1477 * This is the door_server_create(3c) function used to customize
1478 * creation of the threads used in the handling of our daemon's
1479 * door_call(3c)'s.
1480 *
1481 * This function is called synchronously as part of door_create(3c).
1482 * Note that door_create(), however, is not synchronous; it can return
1483 * with the created door file descriptor before any associated
1484 * thread has been created.  As a result, synchronization is needed
1485 * between door_create() caller and the created pthread.  This is
1486 * needed both when each activity succeeds or when either activity
1487 * fails.
1488 *
1489 * Specifically, this function ensures that each "connection"
1490 * with the client creates only one thread in the per-door,
1491 * private thread pool.  This function locks dd_threadlock and
1492 * then calls pthread_create().  If that succeeds, dd_thread
1493 * is assigned the thread id, and dd_threadlock is unlocked.
1494 * Any per-connection door_create that causes control to flow
1495 * to this function will eventually find that dd_thread is
1496 * non-zero, and control will exit this function.
1497 *
1498 * In the current implementation, the door_create for the Client Door
1499 * is called first, and the Death Door is door_create'd second.
1500 * As a result, the following function can safely make the static
1501 * assumption that the first door (within a connection) is the
1502 * Client Door.  A connection's Client Door and Death Door share
1503 * the same thread as well as the same door_data_t instance.
1504 */
1505static void
1506sm_door_server_create(door_info_t *dip)
1507{
1508	door_data_t	*door_dp;
1509	pthread_t	tid;
1510	pthread_attr_t	attr;
1511	int		ret_val;
1512	int		err;
1513
1514	if (dip == NULL) {
1515		return;
1516	}
1517	door_dp = (door_data_t *)(uintptr_t)dip->di_data;
1518
1519	debug(10, "sm_door_server_create[%d]: entering...\n", pthread_self());
1520
1521	/* create one thread for this door */
1522
1523	(void) mutex_lock(&door_dp->dd_threadlock);
1524
1525	if (door_dp->dd_thread != 0) {
1526		debug(8, "sm_door_server_create[%d]: Exiting without creating "
1527		    "thread.\n", pthread_self());
1528		(void) mutex_unlock(&door_dp->dd_threadlock);
1529		return;
1530	}
1531
1532	(void) pthread_attr_init(&attr);
1533
1534	if ((err = pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM)) != 0)
1535		warning(gettext("pthread_attr_setscope failed = %d\n"), err);
1536	if ((err = pthread_attr_setdetachstate(&attr,
1537	    PTHREAD_CREATE_DETACHED)) != 0)
1538		warning(gettext("pthread_attr_setdetachstate failed = %d\n"),
1539		    err);
1540
1541	ret_val = pthread_create(&tid, &attr, sm_server_thread,
1542	    (void *)(uintptr_t)(dip->di_data));
1543	if (ret_val != 0) {
1544		warning(gettext("sm_door_server_create[%d]: pthread_create "
1545		    "failed = %d\n"), pthread_self(), ret_val);
1546		(void) mutex_unlock(&door_dp->dd_threadlock);
1547		(void) pthread_attr_destroy(&attr);
1548		return;
1549	}
1550	(void) pthread_attr_destroy(&attr);
1551	door_dp->dd_thread = tid;
1552
1553	(void) mutex_unlock(&door_dp->dd_threadlock);
1554	debug(5, "Exiting sm_door_server_create[%d] after creating thr[%d].\n",
1555	    pthread_self(), tid);
1556}
1557
1558static void
1559door_ret_err(smedia_reterror_t *reterror, int32_t err)
1560{
1561	reterror->cnum = SMEDIA_CNUM_ERROR;
1562	reterror->errnum = err;
1563	(void) door_return((char *)reterror, sizeof (smedia_reterror_t), 0, 0);
1564}
1565
1566static void
1567my_door_return(char *data_ptr, size_t data_size,
1568	door_desc_t *desc_ptr, uint_t num_desc)
1569{
1570	(void) door_return(data_ptr, data_size, desc_ptr, num_desc);
1571}
1572
1573static int32_t
1574raw_read(door_data_t *door_dp, smedia_services_t *req)
1575{
1576	struct uscsi_cmd	ucmd;
1577	union scsi_cdb		cdb;
1578	int32_t			ret_val;
1579	int32_t			num_sectors, sector_size;
1580	int32_t			rc_data[2];
1581	char			rq_data[RQ_LEN];
1582
1583	(void) memset((void *) &rc_data, 0, sizeof (rc_data));
1584	(void) memset((void *) &ucmd, 0, sizeof (ucmd));
1585	(void) memset((void *) &cdb, 0, sizeof (union scsi_cdb));
1586
1587	if (door_dp->dd_sector_size == 0) {
1588		sector_size = get_sector_size(door_dp->dd_fd);
1589		door_dp->dd_sector_size = sector_size;
1590	} else sector_size = door_dp->dd_sector_size;
1591
1592	if ((req->reqraw_read.nbytes > door_dp->dd_buf_len) ||
1593		(door_dp->dd_buf == NULL)) {
1594		errno = EINVAL;
1595		return (-1);
1596	}
1597	if ((!req->reqraw_read.nbytes) ||
1598		(req->reqraw_read.nbytes % sector_size)) {
1599		errno = EINVAL;
1600		return (-1);
1601	}
1602
1603	(void) memset((void *) &cdb, 0, sizeof (cdb));
1604	num_sectors = (uint32_t)req->reqraw_read.nbytes/sector_size;
1605
1606	cdb.scc_cmd = SCMD_READ_G1;
1607	FORMG1ADDR(&cdb, (uint32_t)req->reqraw_read.blockno);
1608	FORMG1COUNT(&cdb, num_sectors);
1609
1610	ucmd.uscsi_cdb = (caddr_t)&cdb;
1611	ucmd.uscsi_cdblen = CDB_GROUP1;
1612	ucmd.uscsi_bufaddr = (caddr_t)door_dp->dd_buf;
1613	ucmd.uscsi_buflen = (uint32_t)req->reqraw_read.nbytes;
1614	ucmd.uscsi_timeout = 120;	/* If 0, HBA hangs forever */
1615	ucmd.uscsi_rqlen = RQ_LEN;
1616	ucmd.uscsi_rqbuf = rq_data;
1617	ret_val = do_uscsi_cmd(door_dp->dd_fd,
1618		&ucmd, USCSI_READ|USCSI_RQENABLE);
1619	if (ret_val || ucmd.uscsi_status) {
1620		debug(5, "read failed: %d - %d errno = %d\n",
1621			ret_val, ucmd.uscsi_status, errno);
1622		debug(5, "buflen = 0x%x resid = 0x%x sector size = %d\n",
1623			ucmd.uscsi_buflen, ucmd.uscsi_resid, sector_size);
1624		debug(5, "cdb addr: %x %x %x %x \n", cdb.g1_addr3,
1625			cdb.g1_addr2, cdb.g1_addr1, cdb.g1_addr0);
1626		debug(5, "cdb count: %x %x\n", cdb.g1_count1,
1627			cdb.g1_count0);
1628		return (-1);
1629	}
1630	ret_val = ucmd.uscsi_buflen - ucmd.uscsi_resid;
1631	return (ret_val);
1632}
1633
1634static int32_t
1635raw_write(door_data_t *door_dp, smedia_services_t *req)
1636{
1637	struct uscsi_cmd	ucmd;
1638	union scsi_cdb		cdb;
1639	int32_t			ret_val;
1640	int32_t			num_sectors, sector_size;
1641	int32_t			rc_data[2];
1642	char			rq_data[RQ_LEN];
1643
1644	(void) memset((void *) &rc_data, 0, sizeof (rc_data));
1645	(void) memset((void *) &ucmd, 0, sizeof (ucmd));
1646	(void) memset((void *) &cdb, 0, sizeof (union scsi_cdb));
1647
1648	if (door_dp->dd_sector_size == 0) {
1649		sector_size = get_sector_size(door_dp->dd_fd);
1650		door_dp->dd_sector_size = sector_size;
1651	} else sector_size = door_dp->dd_sector_size;
1652
1653
1654	if ((req->reqraw_write.nbytes > door_dp->dd_buf_len) ||
1655		(door_dp->dd_buf == NULL)) {
1656		errno = EINVAL;
1657		return (-1);
1658	}
1659	if ((req->reqraw_write.nbytes % sector_size)) {
1660		errno = EINVAL;
1661		return (-1);
1662	}
1663
1664	(void) memset((void *) &cdb, 0, sizeof (cdb));
1665	num_sectors = (uint32_t)req->reqraw_write.nbytes/sector_size;
1666
1667	cdb.scc_cmd = SCMD_WRITE_G1;
1668	FORMG1ADDR(&cdb, (uint32_t)req->reqraw_write.blockno);
1669	FORMG1COUNT(&cdb, num_sectors);
1670
1671	ucmd.uscsi_cdb = (caddr_t)&cdb;
1672	ucmd.uscsi_cdblen = CDB_GROUP1;
1673	ucmd.uscsi_bufaddr = (caddr_t)door_dp->dd_buf;
1674	ucmd.uscsi_buflen = (uint32_t)req->reqraw_write.nbytes;
1675	ucmd.uscsi_timeout = 120;	/* If 0, HBA hangs forever */
1676	ucmd.uscsi_rqlen = RQ_LEN;
1677	ucmd.uscsi_rqbuf = rq_data;
1678	ret_val = do_uscsi_cmd(door_dp->dd_fd,
1679		&ucmd, USCSI_WRITE|USCSI_RQENABLE);
1680	if (ret_val || ucmd.uscsi_status) {
1681		debug(5, "write failed: %d - %d errno = %d\n",
1682			ret_val, ucmd.uscsi_status, errno);
1683		debug(5, "buflen = 0x%x resid = 0x%x sector size = %d\n",
1684			ucmd.uscsi_buflen, ucmd.uscsi_resid, sector_size);
1685		debug(5, "cdb addr: %x %x %x %x \n", cdb.g1_addr3,
1686			cdb.g1_addr2, cdb.g1_addr1, cdb.g1_addr0);
1687		debug(5, "cdb count: %x %x\n", cdb.g1_count1,
1688			cdb.g1_count0);
1689		return (-1);
1690	}
1691	ret_val = ucmd.uscsi_buflen - ucmd.uscsi_resid;
1692	return (ret_val);
1693}
1694
1695static int32_t
1696set_protection_status(door_data_t *door_dp, smedia_services_t *req)
1697{
1698	int32_t			ret_val, saved_errno, status;
1699	struct scsi_inquiry	inq;
1700	char			vid[9];
1701	char			pid[17];
1702	struct passwd		*pwd;
1703	char			uname[MAXUGNAME + 1];
1704	char			*new_state, *old_state;
1705
1706	/*
1707	 * Read the current protection state before modifiying.
1708	 * Needed for audit purposes.
1709	 */
1710	switch (get_device_type_scsi(door_dp->dd_fd, &inq)) {
1711	case SCSI_IOMEGA:
1712		status = scsi_zip_media_status(door_dp->dd_fd);
1713		ret_val = scsi_zip_write_protect(door_dp->dd_fd,
1714			&req->reqset_protection_status.prot_state);
1715		break;
1716	case SCSI_FLOPPY:
1717		info("Formatting floppy");
1718		status = scsi_floppy_media_status(door_dp->dd_fd);
1719		ret_val = scsi_floppy_write_protect(door_dp->dd_fd,
1720			&req->reqset_protection_status.prot_state);
1721		break;
1722	case SCSI_GENERIC:
1723		status = scsi_media_status(door_dp->dd_fd);
1724		ret_val = scsi_write_protect(door_dp->dd_fd,
1725			&req->reqset_protection_status.prot_state);
1726		break;
1727	}
1728
1729	saved_errno = errno;
1730	new_state = xlate_state(
1731	    req->reqset_protection_status.prot_state.sm_new_state);
1732	old_state = xlate_state(status);
1733
1734	if (can_audit()) {
1735		(void) audit_save_me(door_dp);
1736		door_dp->audit_text[0] = 0;
1737		door_dp->audit_text1[0] = 0;
1738		door_dp->audit_event = AUE_smserverd;
1739	}
1740	(void) strlcpy(vid, inq.inq_vid, sizeof (vid));
1741	(void) strlcpy(pid, inq.inq_pid, sizeof (pid));
1742	if (ret_val < 0) {
1743	    if (errno == EACCES) {
1744		pwd = getpwuid(door_dp->dd_cred.dc_ruid);
1745		if (pwd != NULL) {
1746			(void) strlcpy(uname,
1747				pwd->pw_name, MAXUGNAME);
1748		} else uname[0] = 0;
1749
1750		if (can_audit()) {
1751			(void) snprintf(door_dp->audit_text,
1752				sizeof (door_dp->audit_text),
1753				dgettext(TEXT_DOMAIN, "from %s to %s"),
1754				old_state, new_state);
1755
1756			(void) snprintf(door_dp->audit_text1,
1757				sizeof (door_dp->audit_text1),
1758				"%s %s (%d,%d)", vid, pid,
1759				(int)major(door_dp->dd_stat.st_rdev),
1760				(int)minor(door_dp->dd_stat.st_rdev));
1761
1762			door_dp->audit_sorf = 1;
1763			if (audit_audit(door_dp) == -1)
1764			    warning("Error in writing audit info\n");
1765		}
1766	    } /* errno == EACCES */
1767	    errno = saved_errno;
1768	    return (-1);
1769	}
1770	if (can_audit()) {
1771		(void) snprintf(door_dp->audit_text,
1772			sizeof (door_dp->audit_text),
1773			dgettext(TEXT_DOMAIN, "from %s to %s"),
1774			old_state, new_state);
1775
1776		(void) snprintf(door_dp->audit_text1,
1777			sizeof (door_dp->audit_text1),
1778			"%s %s (%d,%d)", vid, pid,
1779			(int)major(door_dp->dd_stat.st_rdev),
1780			(int)minor(door_dp->dd_stat.st_rdev));
1781
1782		door_dp->audit_sorf = 0;
1783		if (audit_audit(door_dp) == -1)
1784		    warning("Error in writing audit info\n");
1785	}
1786	errno = saved_errno;
1787	return (0);
1788}
1789
1790static int32_t
1791set_shfd(door_data_t *door_dp, int32_t fd, smedia_services_t *req)
1792{
1793	void	*fbuf;
1794	int32_t ret_val = 0;
1795
1796	if ((door_dp->dd_buffd != -1) && (door_dp->dd_buf != NULL)) {
1797		ret_val = munmap(door_dp->dd_buf, door_dp->dd_buf_len);
1798		if (ret_val == -1)
1799			warning(gettext("munmap failed. errno=%d\n"),
1800			    errno);
1801		(void) close(door_dp->dd_buffd);
1802
1803		door_dp->dd_buffd = -1;
1804		door_dp->dd_buf = 0;
1805		door_dp->dd_buf_len = 0;
1806	}
1807
1808	fbuf = mmap(0, req->reqset_shfd.fdbuf_len,
1809	    PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
1810	if (fbuf == MAP_FAILED) {
1811		ret_val = errno;
1812		debug(5, "mmap failed. errno=%d\n", errno);
1813		return (ret_val);
1814	}
1815	door_dp->dd_buffd = fd;
1816	door_dp->dd_buf = fbuf;
1817	door_dp->dd_buf_len = req->reqset_shfd.fdbuf_len;
1818
1819	return (0);
1820}
1821
1822static int32_t
1823reassign_block(door_data_t *door_dp, smedia_services_t *req)
1824{
1825	struct uscsi_cmd	ucmd;
1826	union scsi_cdb		cdb;
1827	int32_t			ret_val;
1828	int32_t			sector_size;
1829	char			*read_buf;
1830	uchar_t			mode_data[MD_LEN];
1831
1832	if (get_mode_page(door_dp->dd_fd, 0, 1,
1833	    mode_data, MD_LEN) < 0) {
1834		debug(5, "Mode sense failed\n");
1835		ret_val =  scsi_reassign_block(door_dp->dd_fd,
1836		    req->reqreassign_block.blockno);
1837		if (ret_val != 0)
1838			return (-1);
1839		return (0);
1840	}
1841
1842	/*
1843	 * No need to check if enough data is returned for
1844	 * AWRE bit or not.
1845	 * It will be 0 otherwise which needs to reassign the block.
1846	 */
1847	if (!(mode_data[AWRE_OFFSET] & AWRE)) {
1848		debug(5, "AWRE bit not set\n");
1849		ret_val =  scsi_reassign_block(door_dp->dd_fd,
1850			req->reqreassign_block.blockno);
1851		if (ret_val != 0)
1852			return (-1);
1853		return (0);
1854	}
1855	sector_size = (mode_data[BLOCK_LEN_OFFSET] << 16) |
1856		(mode_data[BLOCK_LEN_OFFSET + 1] << 8) |
1857		mode_data[BLOCK_LEN_OFFSET + 2];
1858
1859	debug(5, "REASSIGN BLOCK: sec size = 0x%x\n", sector_size);
1860	read_buf = (char *)malloc(sector_size);
1861	if (read_buf == NULL) {
1862		/* Alloc failed. Atleast reassign the block */
1863		ret_val =  scsi_reassign_block(door_dp->dd_fd,
1864			req->reqreassign_block.blockno);
1865		if (ret_val != 0)
1866			return (-1);
1867		return (0);
1868	}
1869
1870	(void) memset(read_buf, 0, sector_size);
1871	/* Read the sector */
1872	debug(5, "Reading the block %d\n",
1873		(uint32_t)req->reqreassign_block.blockno);
1874
1875	(void) memset((void *) &ucmd, 0, sizeof (ucmd));
1876	(void) memset((void *) &cdb, 0, sizeof (union scsi_cdb));
1877
1878	cdb.scc_cmd = SCMD_READ_G1;
1879	FORMG1ADDR(&cdb, req->reqreassign_block.blockno);
1880	FORMG1COUNT(&cdb, 1);	/* One block */
1881
1882	ucmd.uscsi_cdb = (caddr_t)&cdb;
1883	ucmd.uscsi_cdblen = CDB_GROUP1;
1884	ucmd.uscsi_bufaddr = (caddr_t)read_buf;
1885	ucmd.uscsi_buflen = sector_size;
1886	ucmd.uscsi_timeout = 120;	/* If 0, HBA hangs forever */
1887	(void) do_uscsi_cmd(door_dp->dd_fd, &ucmd, USCSI_READ);
1888
1889	/* Write the data back */
1890
1891	debug(5, "Writing the block %d\n",
1892		(uint32_t)req->reqreassign_block.blockno);
1893	(void) memset((void *) &ucmd, 0, sizeof (ucmd));
1894	(void) memset((void *) &cdb, 0, sizeof (cdb));
1895
1896	cdb.scc_cmd = SCMD_WRITE_G1;
1897	FORMG1ADDR(&cdb, req->reqreassign_block.blockno);
1898	FORMG1COUNT(&cdb, 1);	/* One block */
1899
1900	ucmd.uscsi_cdb = (caddr_t)&cdb;
1901	ucmd.uscsi_cdblen = CDB_GROUP1;
1902	ucmd.uscsi_bufaddr = (caddr_t)read_buf;
1903	ucmd.uscsi_buflen = sector_size;
1904	ucmd.uscsi_timeout = 120;	/* If 0, HBA hangs forever */
1905	ret_val = do_uscsi_cmd(door_dp->dd_fd, &ucmd, USCSI_WRITE);
1906	free(read_buf);
1907	if (ret_val || ucmd.uscsi_status) {
1908		debug(5, "Reassign failed: %d - %d errno = %d\n",
1909			ret_val, ucmd.uscsi_status, errno);
1910		ret_val = scsi_reassign_block(door_dp->dd_fd,
1911			req->reqreassign_block.blockno);
1912		if (ret_val != 0)
1913			return (-1);
1914		return (0);
1915	}
1916
1917	return (0);
1918}
1919
1920static void
1921close_door_descs(door_desc_t *dp, uint_t ndesc)
1922{
1923	while (ndesc > 0) {
1924		int fd = dp->d_data.d_desc.d_descriptor;
1925		if (dp->d_attributes & DOOR_DESCRIPTOR)
1926			(void) close(fd);
1927		dp++;
1928		ndesc--;
1929	}
1930}
1931
1932/*
1933 * This is a Death Door's service procedure.
1934 *
1935 * This procedure is a NOP because the Death Door functionality
1936 * is no longer used and will be removed in the future.
1937 */
1938/*ARGSUSED*/
1939static void
1940death_servproc(void *cookie, char *argp, size_t arg_size,
1941    door_desc_t *dp, uint_t ndesc)
1942{
1943	debug(1, "death_servproc[%d]: argp = 0x%p  "
1944	    "Death Door[%d]\n", pthread_self(), (void *)argp,
1945	    ((door_data_t *)cookie)->dd_ddoor_descriptor);
1946
1947	(void) door_return(NULL, 0, NULL, 0);
1948}
1949
1950/*
1951 * This is a Client Door's service procedure.
1952 *
1953 * This procedure is specified in the door_create() of a Client Door,
1954 * and its functionality represents the bulk of services that the
1955 * rpc.smserverd daemon offers.
1956 */
1957static void
1958client_servproc(void *cookie, char *argp, size_t arg_size,
1959    door_desc_t *dp, uint_t ndesc)
1960{
1961	smedia_services_t	*req;
1962	smedia_services_t	rmsvc;
1963	smedia_reterror_t	reterror;
1964	smedia_retraw_read_t	retraw_read;
1965	struct scsi_inquiry	inq;
1966	struct dk_minfo		media_info;
1967	struct dk_geom		dkgeom;
1968	int32_t			status;
1969	uchar_t			data[18];
1970	int32_t			completed = 0;
1971	door_data_t		*door_dp;
1972	size_t			retbuf_size;
1973	struct uscsi_cmd	ucmd;
1974	union scsi_cdb		cdb;
1975	int32_t			ret_val, err;
1976	char			rq_data[RQ_LEN];
1977	uint_t			nexpected_desc;
1978	struct vtoc		vtoc;
1979	struct extvtoc		extvtoc;
1980
1981	door_dp = (door_data_t *)cookie;
1982	req = (smedia_services_t *)((void *)argp);
1983
1984	debug(10, "client_servproc[%d]...\n", pthread_self());
1985
1986	if (argp == DOOR_UNREF_DATA) {
1987		debug(5, "client_servproc[%d]: req = DOOR_UNREF_DATA\n",
1988		    pthread_self());
1989		debug(5, "Client has exited. Cleaning up resources\n");
1990
1991		(void) mutex_lock(&svcstate_lock);
1992		svccount--;
1993		(void) mutex_unlock(&svcstate_lock);
1994
1995		cleanup(door_dp);
1996		return;
1997	}
1998
1999	(void) mutex_lock(&svcstate_lock);
2000	svcstate = _SERVED;
2001	(void) mutex_unlock(&svcstate_lock);
2002
2003	rmsvc.in.cnum = req->in.cnum;
2004	debug(5, "client_servproc[%d]: req = %s\n", pthread_self(),
2005	    xlate_cnum(req->in.cnum));
2006
2007	/*
2008	 * Our caller may have passed more descriptors than we expected.
2009	 * If so, we silently close (and ignore) them.
2010	 */
2011	nexpected_desc = (req->in.cnum == SMEDIA_CNUM_SET_SHFD) ? 1 : 0;
2012	if (ndesc > nexpected_desc) {
2013		close_door_descs(dp + nexpected_desc, ndesc - nexpected_desc);
2014	}
2015
2016	switch (req->in.cnum) {
2017	default:
2018		debug(5, "client_servproc: unknown command %d\n", req->in.cnum);
2019		door_ret_err(&reterror, ENOTSUP);
2020		break;
2021
2022	case SMEDIA_CNUM_SET_SHFD:
2023		if (ndesc == 0)
2024			door_ret_err(&reterror, EINVAL);
2025		/*
2026		 * Allocate shared memory for this connection.
2027		 * If this connection already has shared memory,
2028		 * deallocate before doing the allocation.
2029		 */
2030		ret_val = set_shfd(door_dp, dp->d_data.d_desc.d_descriptor,
2031		    req);
2032		if (ret_val == 0) {
2033			reterror.cnum = SMEDIA_CNUM_SET_SHFD;
2034			reterror.errnum = 0;
2035
2036			my_door_return((char *)&reterror,
2037				sizeof (smedia_reterror_t), 0, 0);
2038		} else {
2039			(void) close(dp->d_data.d_desc.d_descriptor);
2040			door_ret_err(&reterror, ret_val);
2041		}
2042		break;
2043
2044	case SMEDIA_CNUM_RAW_READ:
2045		debug(10, " arg size = %d blk num=0x%x nbytes = 0x%x \n",
2046			(int)arg_size,
2047			(uint32_t)req->reqraw_read.blockno,
2048			req->reqraw_read.nbytes);
2049		retbuf_size = sizeof (smedia_retraw_read_t);
2050		if (req->reqraw_read.nbytes == 0) {
2051			/* Nothing to write */
2052			rmsvc.retraw_write.nbytes = 0;
2053			my_door_return((char *)&rmsvc,
2054				sizeof (smedia_retraw_write_t), 0, 0);
2055		}
2056		retraw_read.cnum = SMEDIA_CNUM_RAW_READ;
2057		ret_val = raw_read(door_dp, req);
2058		if (ret_val == -1) {
2059			door_ret_err(&reterror, errno);
2060		}
2061		retraw_read.nbytes = ret_val;
2062		my_door_return((char *)&retraw_read, retbuf_size, 0, 0);
2063		break;
2064
2065	case	SMEDIA_CNUM_USCSI_CMD:
2066		retbuf_size = sizeof (smedia_retuscsi_cmd_t);
2067		rmsvc.retuscsi_cmd.cnum = SMEDIA_CNUM_USCSI_CMD;
2068		ucmd.uscsi_flags = req->requscsi_cmd.uscsi_flags;
2069		ucmd.uscsi_cdb = (caddr_t)&req->requscsi_cmd.uscsi_cdb;
2070		ucmd.uscsi_cdblen = req->requscsi_cmd.uscsi_cdblen;
2071		ucmd.uscsi_bufaddr = (caddr_t)door_dp->dd_buf;
2072		ucmd.uscsi_buflen = req->requscsi_cmd.uscsi_buflen;
2073		ucmd.uscsi_timeout = req->requscsi_cmd.uscsi_timeout;
2074		ucmd.uscsi_rqlen = req->requscsi_cmd.uscsi_rqlen;
2075		ucmd.uscsi_rqbuf = (caddr_t)&rmsvc.retuscsi_cmd.uscsi_rqbuf;
2076		debug(5, "USCSI CMD 0x%x requested.\n",
2077		    req->requscsi_cmd.uscsi_cdb[0]);
2078		/*
2079		 * Check the device type and invalid flags specified.
2080		 * We permit operations only on CDROM devices types.
2081		 */
2082		errno = invalid_uscsi_operation(door_dp, &ucmd);
2083		if (errno) {
2084			door_ret_err(&reterror, errno);
2085		}
2086
2087		if ((req->requscsi_cmd.uscsi_buflen) &&
2088		    ((req->requscsi_cmd.uscsi_buflen > door_dp->dd_buf_len) ||
2089		    (door_dp->dd_buf == NULL))) {
2090			debug(5, "uscsi_cmd failed: uscsi_buflen=0x%x "
2091			    "dd_buf_len=0x%x dd_buf=0x%p\n",
2092			    req->requscsi_cmd.uscsi_buflen,
2093			    door_dp->dd_buf_len,
2094			    door_dp->dd_buf);
2095			errno = EINVAL;
2096			door_ret_err(&reterror, errno);
2097		}
2098		ret_val = do_uscsi_cmd(door_dp->dd_fd,
2099			&ucmd, req->requscsi_cmd.uscsi_flags);
2100		rmsvc.retuscsi_cmd.uscsi_status = ucmd.uscsi_status;
2101		rmsvc.retuscsi_cmd.uscsi_resid = ucmd.uscsi_resid;
2102		rmsvc.retuscsi_cmd.uscsi_rqstatus = ucmd.uscsi_rqstatus;
2103		rmsvc.retuscsi_cmd.uscsi_rqresid = ucmd.uscsi_rqresid;
2104		rmsvc.retuscsi_cmd.uscsi_retval = ret_val;
2105		rmsvc.retuscsi_cmd.uscsi_errno = errno;
2106		if (ret_val || ucmd.uscsi_status) {
2107			debug(5, "uscsi_cmd failed: %d - %d errno = %d\n",
2108				ret_val, ucmd.uscsi_status, errno);
2109		}
2110		my_door_return((char *)&rmsvc, retbuf_size, 0, 0);
2111		break;
2112
2113	case SMEDIA_CNUM_RAW_WRITE:
2114		if (req->reqraw_write.nbytes == 0) {
2115			/* Nothing to write */
2116			rmsvc.retraw_write.nbytes = 0;
2117			my_door_return((char *)&rmsvc,
2118				sizeof (smedia_retraw_write_t), 0, 0);
2119		}
2120		ret_val = raw_write(door_dp, req);
2121		if (ret_val == -1)
2122			door_ret_err(&reterror, errno);
2123		rmsvc.retraw_write.nbytes = ret_val;
2124		my_door_return((char *)&rmsvc, sizeof (smedia_retraw_write_t),
2125			0, 0);
2126		break;
2127
2128	case SMEDIA_CNUM_GET_DEVICE_INFO:
2129
2130		(void) memset((void *) &inq, 0, sizeof (inq));
2131		(void) memset((void *) &ucmd, 0, sizeof (ucmd));
2132		(void) memset((void *) &cdb, 0, sizeof (union scsi_cdb));
2133		cdb.scc_cmd = SCMD_INQUIRY;
2134		FORMG0COUNT(&cdb, sizeof (inq));
2135		ucmd.uscsi_cdb = (caddr_t)&cdb;
2136		ucmd.uscsi_cdblen = CDB_GROUP0;
2137		ucmd.uscsi_bufaddr = (caddr_t)&inq;
2138		ucmd.uscsi_buflen = sizeof (inq);
2139		ucmd.uscsi_timeout = 120;	/* If 0, HBA hangs forever */
2140		ucmd.uscsi_rqlen = RQ_LEN;
2141		ucmd.uscsi_rqbuf = rq_data;
2142		ret_val = do_uscsi_cmd(door_dp->dd_fd,
2143			&ucmd, USCSI_READ|USCSI_RQENABLE);
2144		if (ret_val || ucmd.uscsi_status) {
2145			debug(5, "inquiry failed: %d - %d errno = %d\n",
2146				ret_val, ucmd.uscsi_status, errno);
2147			door_ret_err(&reterror, errno);
2148		}
2149
2150		debug(5, "%s\n", inq.inq_vid);
2151		debug(5, "%s\n", rmsvc.retget_device_info.sm_vendor_name);
2152
2153		(void) strlcpy(rmsvc.retget_device_info.sm_vendor_name,
2154			inq.inq_vid, 8);
2155		rmsvc.retget_device_info.sm_vendor_name[8] = 0;
2156		(void) strlcpy(rmsvc.retget_device_info.sm_product_name,
2157			inq.inq_pid, 16);
2158		rmsvc.retget_device_info.sm_product_name[16] = 0;
2159		(void) strlcpy(rmsvc.retget_device_info.sm_firmware_version,
2160			inq.inq_revision, 4);
2161		rmsvc.retget_device_info.sm_firmware_version[4] = ' ';
2162		(void) strlcpy(
2163			&rmsvc.retget_device_info.sm_firmware_version[5],
2164				inq.inq_serial, 12);
2165		rmsvc.retget_device_info.sm_product_name[17] = 0;
2166
2167		rmsvc.retget_device_info.sm_interface_type = IF_SCSI;
2168
2169		debug(5, "Vendor name = %s\n",
2170		    rmsvc.retget_device_info.sm_vendor_name);
2171		debug(5, "product name = %s\n",
2172		    rmsvc.retget_device_info.sm_product_name);
2173		debug(5, "Firmware revision = %s\n",
2174		    rmsvc.retget_device_info.sm_firmware_version);
2175
2176		my_door_return((char *)&rmsvc.retget_device_info,
2177			sizeof (smedia_retget_device_info_t), 0, 0);
2178		break;
2179
2180	case	SMEDIA_CNUM_GET_MEDIUM_PROPERTY:
2181
2182		(void) memset((void *)&rmsvc.retget_medium_property.smprop,
2183			0, sizeof (smmedium_prop_t));
2184
2185		ret_val = ioctl(door_dp->dd_fd, DKIOCGMEDIAINFO, &media_info);
2186
2187		if (ret_val < 0) {
2188			uint32_t capacity;
2189			uint32_t blocksize;
2190			/*
2191			 * Devices may fail DKIOCGMEDIAINFO if an unformed
2192			 * media is inserted. We can get the capacity
2193			 * information from the SCMD_READ_FORMAT_CAP command.
2194			 */
2195
2196			debug(5, "DKIOCGMEDIAINFO failed; using "
2197			    "SCMD_READ_FORMAT_CAP");
2198			ret_val = get_media_capacity(door_dp->dd_fd,
2199			    &capacity, &blocksize);
2200
2201			if (ret_val >= 0) {
2202				media_info.dki_lbsize =	blocksize;
2203				media_info.dki_capacity = capacity;
2204			} else {
2205				debug(5, "SCMD_READ_FORMAT_CAP failed");
2206				door_ret_err(&reterror, errno);
2207			}
2208		}
2209		rmsvc.retget_medium_property.smprop.sm_blocksize =
2210		    media_info.dki_lbsize;
2211		rmsvc.retget_medium_property.smprop.sm_capacity =
2212		    media_info.dki_capacity;
2213
2214		rmsvc.retget_medium_property.smprop.sm_media_type =
2215		    media_info.dki_media_type;
2216		/*
2217		 * These devices show as SCSI devices but we need to treat it
2218		 * differently. so we need a seperate class.
2219		 */
2220		if (get_device_type_scsi(door_dp->dd_fd, &inq) == SCSI_FLOPPY) {
2221			rmsvc.retget_medium_property.smprop.sm_media_type =
2222			    SM_SCSI_FLOPPY;
2223		}
2224
2225		/* Check for EFI type because DKIOCGGEOM does not support EFI */
2226		ret_val = ioctl(door_dp->dd_fd, DKIOCGEXTVTOC, &extvtoc);
2227		if (ret_val < 0 && errno == ENOTTY)
2228			ret_val = ioctl(door_dp->dd_fd, DKIOCGVTOC, &vtoc);
2229
2230		if (!((ret_val < 0) && (errno == ENOTSUP))) {
2231			ret_val = ioctl(door_dp->dd_fd, DKIOCGGEOM, &dkgeom);
2232			if (ret_val < 0)  {
2233				/*
2234				 * DKIOCGGEOM may fail for unformed floppies.
2235				 * We need to generate the appropriate geometry
2236				 * information.
2237				 */
2238				if (rmsvc.retget_medium_property.smprop.
2239				    sm_media_type == SM_SCSI_FLOPPY) {
2240					ret_val = get_floppy_geom(
2241					    door_dp->dd_fd,
2242					    media_info.dki_capacity, &dkgeom);
2243
2244					if (ret_val < 0) {
2245						debug(5, "Cannot determine "
2246						    "media size");
2247						door_ret_err(&reterror, errno);
2248					}
2249				} else {
2250#ifdef sparc
2251					debug(5, "DKIOCGGEOM ioctl failed");
2252					door_ret_err(&reterror, errno);
2253#else /* !sparc */
2254					/*
2255					 * Try getting Physical geometry on x86.
2256					 */
2257					ret_val = ioctl(door_dp->dd_fd,
2258					    DKIOCG_PHYGEOM, &dkgeom);
2259					if (ret_val < 0) {
2260						debug(5, "DKIOCG_PHYGEOM "
2261						    "ioctl failed");
2262						door_ret_err(&reterror, errno);
2263					}
2264#endif /* sparc */
2265				}
2266			}
2267
2268
2269			/*
2270			 * Some faked geometry may not have pcyl filled in so
2271			 * later calculations using this field will be
2272			 * incorrect.  We will substitute it with the number of
2273			 * available cylinders.
2274			 */
2275			if (dkgeom.dkg_pcyl == 0)
2276				rmsvc.retget_medium_property.smprop.sm_pcyl =
2277				    dkgeom.dkg_ncyl;
2278			else
2279				rmsvc.retget_medium_property.smprop.sm_pcyl =
2280				    dkgeom.dkg_pcyl;
2281
2282			rmsvc.retget_medium_property.smprop.sm_nhead =
2283			    dkgeom.dkg_nhead;
2284			rmsvc.retget_medium_property.smprop.sm_nsect =
2285			    dkgeom.dkg_nsect;
2286		}
2287
2288		debug(1, "properties are: lbasize = %d, cap = %llu",
2289		    media_info.dki_lbsize, media_info.dki_capacity);
2290
2291		my_door_return((char *)&rmsvc.retget_medium_property,
2292			sizeof (smedia_retget_medium_property_t), 0, 0);
2293		break;
2294
2295	case	SMEDIA_CNUM_GET_PROTECTION_STATUS:
2296		switch (get_device_type_scsi(door_dp->dd_fd, &inq)) {
2297		case SCSI_FLOPPY:
2298			status = scsi_floppy_media_status(door_dp->dd_fd);
2299			break;
2300		case SCSI_IOMEGA:
2301			status = scsi_zip_media_status(door_dp->dd_fd);
2302			break;
2303		case SCSI_GENERIC:
2304			status = scsi_media_status(door_dp->dd_fd);
2305			break;
2306		default:
2307			door_ret_err(&reterror, errno);
2308		}
2309		if (status < 0)
2310			door_ret_err(&reterror, errno);
2311
2312		rmsvc.retget_protection_status.prot_state.sm_new_state  =
2313			status;
2314
2315		my_door_return((char *)&rmsvc.retget_protection_status,
2316			sizeof (smedia_retget_protection_status_t), 0, 0);
2317		break;
2318
2319	case	SMEDIA_CNUM_SET_PROTECTION_STATUS:
2320
2321		ret_val = set_protection_status(door_dp, req);
2322		if (ret_val == -1)
2323			door_ret_err(&reterror, errno);
2324		else
2325			my_door_return((char *)&rmsvc.retset_protection_status,
2326				sizeof (smedia_retset_protection_status_t),
2327				0, 0);
2328		break;
2329
2330	case SMEDIA_CNUM_FORMAT:
2331		switch (get_device_type_scsi(door_dp->dd_fd, &inq)) {
2332		case SCSI_FLOPPY:
2333			info("formatting floppy");
2334			err = scsi_floppy_format(door_dp->dd_fd,
2335				req->reqformat.flavor, req->reqformat.mode);
2336
2337			break;
2338		case SCSI_IOMEGA:
2339			err = scsi_zip_format(door_dp->dd_fd,
2340				req->reqformat.flavor, req->reqformat.mode);
2341			break;
2342		case SCSI_GENERIC:
2343			err = scsi_format(door_dp->dd_fd,
2344				req->reqformat.flavor, req->reqformat.mode);
2345			break;
2346		default:
2347			door_ret_err(&reterror, ENOTSUP);
2348		}
2349
2350		if (err)
2351			door_ret_err(&reterror, errno);
2352		my_door_return((char *)&rmsvc.retformat,
2353			sizeof (smedia_retformat_t), 0, 0);
2354
2355		break;
2356
2357	case SMEDIA_CNUM_CHECK_FORMAT_STATUS:
2358
2359		(void) memset((void *) &cdb, 0, sizeof (union scsi_cdb));
2360		(void) memset((void *) &ucmd, 0, sizeof (ucmd));
2361		(void) memset((void *) &data, 0, sizeof (data));
2362		cdb.scc_cmd = SCMD_REQUEST_SENSE;
2363		cdb.g0_count0 = sizeof (data);
2364		ucmd.uscsi_cdb = (caddr_t)&cdb;
2365		ucmd.uscsi_cdblen = CDB_GROUP0;
2366		ucmd.uscsi_bufaddr = (caddr_t)&data;
2367		ucmd.uscsi_buflen = sizeof (data);
2368		ucmd.uscsi_timeout = 120;	/* If 0, HBA hangs forever */
2369		ucmd.uscsi_rqlen = RQ_LEN;
2370		ucmd.uscsi_rqbuf = rq_data;
2371		ret_val = do_uscsi_cmd(door_dp->dd_fd,
2372			&ucmd, USCSI_READ|USCSI_RQENABLE);
2373		if (ret_val || ucmd.uscsi_status) {
2374			debug(5, "Request sense failed: %d - %d errno = %d\n",
2375				ret_val, ucmd.uscsi_status, errno);
2376			door_ret_err(&reterror, errno);
2377		}
2378
2379		if ((data[0] & 0x7F) == DEFERRED_ERROR) {
2380		/* Deffered error. The format must have failed */
2381			debug(5, "format failed!\n");
2382			door_ret_err(&reterror, EIO);
2383		}
2384
2385		if (data[SKSV_OFFSET] & SKSV_FIELD) {
2386			completed =
2387				(data[FORMAT_PROGRESS_INDICATOR_OFFSET_0] << 8)
2388				| data[FORMAT_PROGRESS_INDICATOR_OFFSET_1];
2389			completed = (completed*100/65536);
2390		} else {
2391			completed = (100);
2392		}
2393		rmsvc.retcheck_format_status.percent_complete = completed;
2394		my_door_return((char *)&rmsvc.retcheck_format_status,
2395			sizeof (smedia_retcheck_format_status_t), 0, 0);
2396		break;
2397
2398	case SMEDIA_CNUM_REASSIGN_BLOCK:
2399
2400		ret_val = reassign_block(door_dp, req);
2401		if (ret_val == -1)
2402			door_ret_err(&reterror, errno);
2403		my_door_return((char *)&rmsvc.retreassign_block,
2404			sizeof (smedia_retreassign_block_t), 0, 0);
2405		break;
2406
2407	}	/* end of switch */
2408
2409	debug(10, "Exiting client server...\n");
2410	my_door_return((char *)&reterror, sizeof (smedia_reterror_t), 0, 0);
2411}
2412
2413/*
2414 * This is the service procedure for the door that is associated with
2415 * the (doorfs) filesystem Door that is created at 'smedia_service'.
2416 */
2417/*ARGSUSED*/
2418static void
2419main_servproc(void *server_data, char *argp, size_t arg_size,
2420    door_desc_t *dp, uint_t ndesc)
2421{
2422	smedia_services_t	*req;
2423	door_cred_t	door_credentials;
2424	int		ret_val;
2425	door_data_t	*ddata;
2426	smedia_reterror_t	reterror;
2427	smedia_reterror_t	retok;
2428	struct	stat	stat;
2429	door_desc_t	*didpp;
2430	struct dk_cinfo dkinfo;
2431	uint_t		nexpected_desc;
2432
2433	debug(10, "Entering main_servproc[%d].\n", pthread_self());
2434
2435	didpp = dp;
2436	(void) mutex_lock(&svcstate_lock);
2437	svcstate = _SERVED;
2438	(void) mutex_unlock(&svcstate_lock);
2439
2440	reterror.cnum = SMEDIA_CNUM_ERROR;
2441	reterror.errnum = SMEDIA_FAILURE;
2442
2443	if (argp == NULL) {
2444		debug(5, "argp is NULL\n");
2445		if (ndesc > 0)
2446			close_door_descs(dp, ndesc);
2447		my_door_return((char *)&reterror,
2448		    sizeof (smedia_reterror_t), 0, 0);
2449	}
2450
2451	req = (smedia_services_t *)((void *)argp);
2452
2453	retok.cnum = req->in.cnum;
2454	retok.errnum = 0;
2455
2456	debug(5, "req = %s arg_size = 0x%x \n",
2457	    xlate_cnum(req->reqopen.cnum), arg_size);
2458
2459	/*
2460	 * Our caller may have passed more descriptors than we expected.
2461	 * If so, we silently close (and ignore) them.
2462	 */
2463	nexpected_desc = (req->in.cnum == SMEDIA_CNUM_OPEN_FD) ? 1 : 0;
2464	if (ndesc > nexpected_desc) {
2465		close_door_descs(dp + nexpected_desc, ndesc - nexpected_desc);
2466	}
2467
2468	switch (req->in.cnum) {
2469	default:
2470		debug(5, "main_servproc: unknown command 0x%x\n",
2471		    req->reqopen.cnum);
2472		break;
2473
2474	case SMEDIA_CNUM_PING:
2475		/*
2476		 * This service is to indicate that server is up and
2477		 * running. It is usually called from another instance of
2478		 * server that is started.
2479		 */
2480		reterror.cnum = SMEDIA_CNUM_PING;
2481		reterror.errnum = 0;
2482		my_door_return((char *)&reterror,
2483		    sizeof (smedia_reterror_t), 0, 0);
2484		break;
2485
2486
2487	case SMEDIA_CNUM_OPEN_FD:
2488
2489		debug(5, "ndesc = %d\n", ndesc);
2490		if (ndesc == 0) {
2491			my_door_return((char *)&reterror,
2492			    sizeof (smedia_reterror_t), 0, 0);
2493		}
2494		debug(5, "Checking file descriptor of target device\n");
2495		if (fstat(didpp->d_data.d_desc.d_descriptor, &stat) < 0) {
2496			warning(gettext("main_servproc:fstat failed. "
2497			    "errno = %d\n"), errno);
2498			(void) close(didpp->d_data.d_desc.d_descriptor);
2499			my_door_return((char *)&reterror,
2500			    sizeof (smedia_reterror_t), 0, 0);
2501		}
2502		debug(5, "descriptor = %d st_mode = 0x%lx\n",
2503		    didpp->d_data.d_desc.d_descriptor,
2504		    stat.st_mode);
2505
2506		/* Obtain the credentials of the user */
2507		ret_val = door_cred(&door_credentials);
2508		if (ret_val < 0) {
2509			warning(gettext("main_servproc:door_cred "
2510			    "failed. errno = %d\n"), errno);
2511			(void) close(didpp->d_data.d_desc.d_descriptor);
2512			my_door_return((char *)&reterror,
2513			    sizeof (smedia_reterror_t), 0, 0);
2514		}
2515		if (ioctl(didpp->d_data.d_desc.d_descriptor, DKIOCINFO,
2516			&dkinfo) == -1) {
2517			warning(gettext("main_servproc:DKIOCINFO failed. "
2518			    "errno = %d\n"), errno);
2519			(void) close(didpp->d_data.d_desc.d_descriptor);
2520			my_door_return((char *)&reterror,
2521			    sizeof (smedia_reterror_t), 0, 0);
2522		}
2523
2524		ddata = (door_data_t *)calloc(1, sizeof (door_data_t));
2525		if (ddata == NULL) {
2526			warning(gettext("main_servproc:calloc failed. "
2527			    "errno = %d\n"), errno);
2528			(void) close(didpp->d_data.d_desc.d_descriptor);
2529			my_door_return((char *)&reterror,
2530			    sizeof (smedia_reterror_t), 0, 0);
2531		}
2532		ddata->dd_stat = stat;
2533		ddata->dd_cred = door_credentials;
2534		ddata->dd_fd = didpp->d_data.d_desc.d_descriptor;
2535		ddata->dd_buf = NULL;
2536		ddata->dd_buf_len = 0;
2537		ddata->dd_buffd = -1;
2538		ddata->dd_sector_size = 0;
2539		ddata->dd_dkinfo = dkinfo;
2540		debug(5, "ddata = 0x%p \n", (void *)ddata);
2541
2542		/* specify a function that'll customize our door threads */
2543		(void) door_server_create(sm_door_server_create);
2544		debug(5, "door_server_create called.\n");
2545
2546		(void) mutex_lock(&ddata->dd_lock);
2547
2548		/* create Client Door */
2549		ddata->dd_cdoor_descriptor =
2550		    door_create(client_servproc,
2551		    (void *)ddata, DOOR_PRIVATE | DOOR_NO_CANCEL | DOOR_UNREF);
2552
2553		if (ddata->dd_cdoor_descriptor < 0) {
2554			/* then door_create() failed */
2555			int err = errno;
2556
2557			(void) mutex_unlock(&ddata->dd_lock);
2558
2559			warning(gettext("main_servproc: door_create of Client "
2560			    "Door failed = %d\n"), err);
2561			free(ddata);
2562
2563			/* close target device */
2564			(void) close(didpp->d_data.d_desc.d_descriptor);
2565			my_door_return((char *)&reterror,
2566			    sizeof (smedia_reterror_t), 0, 0);
2567		}
2568
2569		/* create Death Door */
2570		ddata->dd_ddoor_descriptor =
2571		    door_create(death_servproc, (void *)ddata,
2572		    DOOR_REFUSE_DESC | DOOR_NO_CANCEL);
2573		if (ddata->dd_ddoor_descriptor < 0) {
2574			warning(gettext("main_servproc: door_create of Death "
2575			    "Door failed = %d\n"), errno);
2576		} else {
2577			(void) door_setparam(ddata->dd_ddoor_descriptor,
2578			    DOOR_PARAM_DATA_MAX, 0);
2579		}
2580
2581		debug(5, "main_servproc[%d]: Client Door = %d, "
2582		    "Death Door = %d", pthread_self(),
2583		    ddata->dd_cdoor_descriptor, ddata->dd_ddoor_descriptor);
2584
2585		audit_init(ddata);
2586
2587		/* wait until sm_server_thread does door_bind() */
2588		(void) cond_wait(&ddata->dd_cv_bind, &ddata->dd_lock);
2589
2590		(void) mutex_unlock(&ddata->dd_lock);
2591
2592		(void) mutex_lock(&svcstate_lock);
2593		svccount++;
2594		(void) mutex_unlock(&svcstate_lock);
2595
2596		if (ddata->dd_ddoor_descriptor < 0) {
2597			/* Return only the Client Door to the client. */
2598			ddata->dd_cdoor.d_attributes = (DOOR_DESCRIPTOR);
2599			my_door_return((char *)&reterror,
2600			    sizeof (smedia_reterror_t), &ddata->dd_desc[0], 1);
2601		} else {
2602			/*
2603			 * Return the Client Door and Death Door
2604			 * to the client.
2605			 */
2606			debug(5, "retok.cnum = 0x%x\n", retok.cnum);
2607			ddata->dd_cdoor.d_attributes = (DOOR_DESCRIPTOR);
2608			ddata->dd_ddoor.d_attributes = (DOOR_DESCRIPTOR);
2609			my_door_return((char *)&retok,
2610			    sizeof (smedia_reterror_t), &ddata->dd_desc[0], 2);
2611		}
2612		break;
2613	}
2614
2615	debug(10, "exiting main_servproc. \n");
2616	my_door_return((char *)&reterror, sizeof (smedia_reterror_t), 0, 0);
2617}
2618
2619/* ARGSUSED */
2620static void
2621term_handler(int sig, siginfo_t *siginfo, void *sigctx)
2622{
2623	warning(gettext("thread[%d]: Received signal %d. Ignoring it.\n"),
2624	    pthread_self(),
2625	    sig);
2626}
2627
2628/* ARGSUSED */
2629static void
2630hup_handler(int sig, siginfo_t *siginfo, void *sigctx)
2631{
2632	warning(gettext("thread[%d]: Received signal %d. Ignoring it.\n"),
2633	    pthread_self(),
2634	    sig);
2635}
2636
2637/*ARGSUSED*/
2638static void
2639sig_handler(int sig, siginfo_t *siginfo, void *sigctx)
2640{
2641	warning(gettext("thread[%d]: Received signal %d. Ignoring it.\n"),
2642	    pthread_self(),
2643	    sig);
2644}
2645
2646/*ARGSUSED*/
2647static void
2648badsig_handler(int sig, siginfo_t *siginfo, void *sigctx)
2649{
2650	fatal(BADSIG_MSG, pthread_self(), sig, siginfo->si_addr,
2651	    siginfo->si_trapno,
2652	    siginfo->si_pc);
2653}
2654
2655/*ARGSUSED*/
2656static void *
2657init_server(void *argp)
2658{
2659	int	i, fd;
2660	struct	sigaction	act;
2661	struct	rlimit		rlim;
2662
2663	debug(10, "init_server  running\n");
2664
2665	(void) setlocale(LC_ALL, "");
2666#if !defined(TEXT_DOMAIN)
2667#define	TEXT_DOMAIN "SYS_TEST"
2668#endif
2669	(void) textdomain(TEXT_DOMAIN);
2670
2671
2672	if (geteuid() != 0) fatal("Must be root to execute smserverd\n");
2673
2674
2675	/*
2676	 * setup signal handlers.
2677	 */
2678
2679	for (i = 0; i < N_BADSIGS; i++) {
2680		act.sa_sigaction = badsig_handler;
2681		(void) sigemptyset(&act.sa_mask);
2682		act.sa_flags = SA_SIGINFO;
2683		if (sigaction(badsigs[i], &act, NULL) == -1)
2684			warning(gettext(SIGACT_FAILED), strsignal(badsigs[i]),
2685				strerror(errno));
2686	}
2687
2688	/*
2689	 * Ignore SIGHUP until all the initialization is done.
2690	 */
2691	act.sa_handler = SIG_IGN;
2692	(void) sigemptyset(&act.sa_mask);
2693	act.sa_flags = 0;
2694	if (sigaction(SIGHUP, &act, NULL) == -1)
2695		warning(gettext(SIGACT_FAILED), strsignal(SIGHUP),
2696			strerror(errno));
2697	/*
2698	 * Increase file descriptor limit to the most it can possibly
2699	 * be.
2700	 */
2701	if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) {
2702		warning(gettext("getrlimit for fd's failed; %m\n"));
2703	}
2704
2705	rlim.rlim_cur = rlim.rlim_max;
2706
2707	if (setrlimit(RLIMIT_NOFILE, &rlim) < 0) {
2708		warning(gettext("setrlimit for fd's failed; %m\n"));
2709	}
2710	(void) enable_extended_FILE_stdio(-1, -1);
2711
2712	server_door = door_create(main_servproc, (void *)&server_data, 0);
2713	if (server_door == -1) {
2714		debug(1, "main door_create");
2715		exit(1);
2716	}
2717
2718	(void) unlink(smedia_service);
2719	fd = open(smedia_service, O_RDWR|O_CREAT|O_EXCL, 0644);
2720	if (fd < 0) {
2721		debug(5, "could not open %s.\n", smedia_service);
2722		exit(1);
2723	}
2724	(void) close(fd);
2725	server_fd = fattach(server_door, smedia_service);
2726	if (server_fd == -1) {
2727		debug(1, "main fattach");
2728		exit(1);
2729	}
2730	server_data.sd_door = server_door;
2731	server_data.sd_fd = server_fd;
2732
2733	/*
2734	 * setup signal handlers for post-init
2735	 */
2736
2737	act.sa_sigaction = hup_handler;
2738	(void) sigemptyset(&act.sa_mask);
2739	act.sa_flags = SA_SIGINFO;
2740	if (sigaction(SIGHUP, &act, NULL) == -1)
2741		warning(gettext(SIGACT_FAILED), strsignal(SIGHUP),
2742		    strerror(errno));
2743
2744	act.sa_sigaction = term_handler;
2745	(void) sigemptyset(&act.sa_mask);
2746	act.sa_flags = SA_SIGINFO;
2747	if (sigaction(SIGTERM, &act, NULL) == -1)
2748		warning(gettext(SIGACT_FAILED), strsignal(SIGTERM),
2749		    strerror(errno));
2750
2751	act.sa_sigaction = sig_handler;
2752	(void) sigemptyset(&act.sa_mask);
2753	act.sa_flags = SA_SIGINFO;
2754	if (sigaction(SIGINT, &act, NULL) == -1)
2755		warning(gettext(SIGACT_FAILED), strsignal(SIGHUP),
2756		    strerror(errno));
2757
2758	act.sa_sigaction = sig_handler;
2759	(void) sigemptyset(&act.sa_mask);
2760	act.sa_flags = SA_SIGINFO;
2761	if (sigaction(SIGQUIT, &act, NULL) == -1)
2762		warning(gettext(SIGACT_FAILED), strsignal(SIGHUP),
2763		    strerror(errno));
2764	debug(10, "init_server completed successfully\n");
2765
2766	server_data.sd_init_state = INIT_DONE;
2767	return (NULL);
2768}
2769
2770static int
2771server_exists()
2772{
2773	door_arg_t		darg;
2774	smedia_reqping_t	req_ping;
2775	smedia_retping_t	*ret_ping;
2776	int			doorh;
2777	door_info_t		dinfo;
2778	char    rbuf[sizeof (smedia_services_t) + sizeof (door_desc_t)];
2779
2780	doorh = open(smedia_service, O_RDONLY);
2781	if (doorh < 0)
2782		return (0);
2783	if (door_info(doorh, &dinfo) < 0) {
2784		(void) close(doorh);
2785		return (0);
2786	}
2787	if (dinfo.di_attributes & DOOR_REVOKED) {
2788		(void) close(doorh);
2789		return (0);
2790	}
2791
2792	req_ping.cnum = SMEDIA_CNUM_PING;
2793
2794	darg.data_ptr = (char *)&req_ping;
2795	darg.data_size = sizeof (smedia_reqping_t);
2796	darg.desc_ptr = NULL;
2797	darg.desc_num = 0;
2798	darg.rbuf = rbuf;
2799	darg.rsize = sizeof (rbuf);
2800
2801	if (door_call(doorh, &darg) < 0) {
2802		(void) close(doorh);
2803		return (0);
2804	}
2805	ret_ping = (smedia_retping_t *)((void *)darg.data_ptr);
2806	if (ret_ping->cnum != SMEDIA_CNUM_PING) {
2807		(void) close(doorh);
2808		return (0);
2809	}
2810
2811	(void) close(doorh);
2812	return (1);
2813}
2814
2815static int
2816get_run_level()
2817{
2818	int	run_level;
2819	struct utmpx	*utmpp;
2820
2821	setutxent();
2822	while ((utmpp = getutxent()) != NULL) {
2823		if (utmpp->ut_type == RUN_LVL) {
2824			run_level = atoi(
2825				&utmpp->ut_line[strlen("run-level ")]);
2826		}
2827	}
2828	return (run_level);
2829}
2830
2831/*ARGSUSED*/
2832static void *
2833closedown(void *arg)
2834{
2835
2836	int	current_run_level;
2837
2838	/*CONSTCOND*/
2839#ifndef lint
2840	while (1) {
2841#endif
2842		(void) sleep(SVC_CLOSEDOWN/2);
2843
2844		/*
2845		 * If the server was started at init level 1
2846		 * and the current init level is 1 then
2847		 * do not exit from server. This server will run
2848		 * until it is explicitly stopped by the user.
2849		 */
2850		if (svcstart_level == 1) {
2851			current_run_level = get_run_level();
2852			if (current_run_level == 1)
2853#ifndef lint
2854				continue;
2855#else
2856				return (NULL);
2857#endif
2858			/*
2859			 * who ever started the server at level 1 has
2860			 * forgotten to stop the server. we will kill ourself.
2861			 */
2862			debug(5,
2863			"Terminating the server started at init level 1\n");
2864			exit(0);
2865		}
2866
2867		if (mutex_trylock(&svcstate_lock) != 0)
2868#ifndef lint
2869			continue;
2870#else
2871			return (NULL);
2872#endif
2873		if (svcstate == _IDLE && svccount == 0) {
2874			int size;
2875			int i, openfd = 0;
2876
2877			size = svc_max_pollfd;
2878			for (i = 0; i < size && openfd < 2; i++)
2879				if (svc_pollfd[i].fd >= 0)
2880					openfd++;
2881			if (openfd <= 1) {
2882				debug(5,
2883				"Exiting the server from closedown routine.\n");
2884				exit(0);
2885			}
2886		} else
2887			svcstate = _IDLE;
2888
2889		(void) mutex_unlock(&svcstate_lock);
2890#ifndef lint
2891	}
2892#else
2893	return (NULL);
2894#endif
2895
2896}
2897
2898static void
2899usage()
2900{
2901	warning(gettext("usage: %s [-L loglevel] level of debug information\n"),
2902		prog_name);
2903}
2904
2905
2906/*ARGSUSED*/
2907int
2908main(int argc, char **argv)
2909{
2910	int c;
2911	pthread_attr_t	attr;
2912
2913	(void) setlocale(LC_ALL, "");
2914#if !defined(TEXT_DOMAIN)
2915#define	TEXT_DOMAIN "SYS_TEST"
2916#endif
2917	(void) textdomain(TEXT_DOMAIN);
2918
2919	prog_name = argv[0];
2920
2921	(void) sigset(SIGPIPE, SIG_IGN);
2922
2923	while ((c = getopt(argc, argv, "L:")) != -1) {
2924		switch (c) {
2925		case 'L':
2926			debug_level = atoi((char *)optarg);
2927			break;
2928		default:
2929			usage();
2930			break;
2931		}
2932	}
2933
2934	/*
2935	 * If stdin looks like a TLI endpoint, we assume
2936	 * that we were started by a port monitor. If
2937	 * t_getstate fails with TBADF, this is not a
2938	 * TLI endpoint.
2939	 */
2940	if (t_getstate(0) != -1 || t_errno != TBADF) {
2941		char *netid;
2942		struct netconfig *nconf = NULL;
2943		SVCXPRT *transp;
2944		int pmclose;
2945
2946		openlog(prog_name, LOG_PID, LOG_DAEMON);
2947
2948		debug(1, gettext("server started by port monitor.\n"));
2949		if ((netid = getenv("NLSPROVIDER")) == NULL) {
2950		/* started from inetd */
2951			pmclose = 1;
2952		} else {
2953			if ((nconf = getnetconfigent(netid)) == NULL)
2954				syslog(LOG_ERR, gettext(
2955					"cannot get transport info"));
2956
2957			pmclose = (t_getstate(0) != T_DATAXFER);
2958		}
2959		if ((transp = svc_tli_create(0, nconf, NULL, 0, 0)) == NULL) {
2960			syslog(LOG_ERR, gettext("cannot create server handle"));
2961			exit(1);
2962		}
2963		if (nconf)
2964			freenetconfigent(nconf);
2965		if (!svc_reg(transp, SMSERVERPROG, SMSERVERVERS,
2966			smserverprog_1, 0)) {
2967			syslog(LOG_ERR, gettext(
2968			"unable to register (SMSERVERPROG, SMSERVERVERS)."));
2969			exit(1);
2970		}
2971		svcstart_level = get_run_level();
2972		if (pmclose) {
2973			(void) pthread_attr_init(&attr);
2974			(void) pthread_attr_setscope(&attr,
2975			    PTHREAD_SCOPE_SYSTEM);
2976			(void) pthread_attr_setdetachstate(&attr,
2977			    PTHREAD_CREATE_DETACHED);
2978			if (pthread_create(NULL, &attr, closedown, NULL) != 0) {
2979				syslog(LOG_ERR, gettext(
2980					"cannot create closedown thread"));
2981				exit(1);
2982			}
2983			(void) pthread_attr_destroy(&attr);
2984		}
2985		svc_run();
2986		exit(1);
2987		/* NOTREACHED */
2988	} else {
2989		/*
2990		 * Started by library or manually.
2991		 */
2992		/*
2993		 * Check to see if the server is already running.
2994		 * There is no need to log messages in the syslog file
2995		 * because server will get launched each time libsmedia
2996		 * library calls are made at init 1 level.
2997		 * We ensure that only one copy will run.
2998		 */
2999		debug(1, gettext("server started manually.\n"));
3000		if (server_exists()) {
3001			exit(0);
3002		}
3003		svcstart_level = get_run_level();
3004		(void) pthread_attr_init(&attr);
3005		(void) pthread_attr_setscope(&attr,
3006		    PTHREAD_SCOPE_SYSTEM);
3007		(void) pthread_attr_setdetachstate(&attr,
3008		    PTHREAD_CREATE_DETACHED);
3009		if (pthread_create(NULL, &attr, closedown, NULL) != 0) {
3010			syslog(LOG_ERR, gettext(
3011				"cannot create closedown thread"));
3012			exit(1);
3013		}
3014		(void) pthread_attr_destroy(&attr);
3015		(void) init_server(NULL);
3016		for (;;) (void) pause();
3017	}
3018	return (0);
3019}
3020
3021
3022/*ARGSUSED*/
3023static int32_t
3024scsi_floppy_write_protect(int32_t fd, smwp_state_t *wp)
3025{
3026	debug(5, "Invalid mode\n");
3027	errno = ENOTSUP;
3028
3029	return (-1);
3030}
3031
3032/*
3033 * Generate standard geometry information for SCSI floppy devices. And
3034 * register the geometry with the SCSI driver. This will expand as more
3035 * formats are added.
3036 */
3037
3038/*ARGSUSED*/
3039static int32_t
3040get_floppy_geom(int32_t fd, uint32_t capacity, struct dk_geom *dkgeom)
3041{
3042
3043
3044	debug(5, "get_floppy_geom: capacity = 0x%x\n", capacity);
3045
3046	switch (capacity) {
3047
3048		case 0x5A0:
3049			/* Double Density 720K */
3050			dkgeom->dkg_pcyl = 80;
3051			dkgeom->dkg_ncyl = 80;
3052			dkgeom->dkg_nhead = 2;
3053			dkgeom->dkg_nsect = 9;
3054			break;
3055		case 0x4D0:
3056			/* High Density 1.25MB */
3057			dkgeom->dkg_pcyl = 77;
3058			dkgeom->dkg_ncyl = 77;
3059			dkgeom->dkg_nhead = 2;
3060			dkgeom->dkg_nsect = 9;
3061			break;
3062		case 0xB40:
3063			/* High Density 1.44MB */
3064
3065			dkgeom->dkg_pcyl = 80;
3066			dkgeom->dkg_ncyl = 80;
3067			dkgeom->dkg_nhead = 2;
3068			dkgeom->dkg_nsect = 18;
3069			break;
3070		case 0x3C300:
3071			/* Ultra High density ls-120 120MB */
3072			dkgeom->dkg_pcyl = 963;
3073			dkgeom->dkg_ncyl = 963;
3074			dkgeom->dkg_nhead = 8;
3075			dkgeom->dkg_nsect = 32;
3076			break;
3077		default:
3078			debug(5, "unknown capacity type %d\n", capacity);
3079			return (-1);
3080
3081	}
3082	debug(5, "get_floppy_geom: setting cyl = %d, nsect = %d, head = %d",
3083		dkgeom->dkg_pcyl, dkgeom->dkg_nhead, dkgeom->dkg_nsect);
3084	return (0);
3085
3086}
3087/* ARGSUSED */
3088static int32_t
3089scsi_floppy_format(int32_t fd, uint_t flavor, uint_t mode)
3090{
3091	struct uscsi_cmd ucmd;
3092	uchar_t		cdb[12];
3093	int32_t		ret_val;
3094	uint32_t	capacity, blocksize;
3095	uchar_t		data[12];
3096	char 		rq_data[RQ_LEN];
3097	int		i;
3098	struct dk_geom	dkgeom;
3099
3100	debug(5, "scsi_floppy_format:\n");
3101
3102	if ((mode != SM_FORMAT_IMMEDIATE) && (mode != SM_FORMAT_BLOCKED)) {
3103		errno = ENOTSUP;
3104
3105		return (-1);
3106	}
3107
3108	switch (flavor) {
3109		case SM_FORMAT_QUICK :
3110			debug(1, "Format not supported\n");
3111			errno = ENOTSUP;
3112			return (-1);
3113		case SM_FORMAT_FORCE :
3114			break;
3115		case SM_FORMAT_LONG :
3116			break;
3117
3118		default :
3119			debug(1, "Format option not specified!!\n");
3120			errno = ENOTSUP;
3121			return (-1);
3122	}
3123
3124	ret_val = get_media_capacity(fd, &capacity, &blocksize);
3125
3126	if (capacity >= 0x3C300) {
3127		/*
3128		 * It's an LS-120 media, it does not support track
3129		 * formatting.
3130		 */
3131		return (scsi_ls120_format(fd, flavor, capacity, blocksize));
3132	}
3133
3134	ret_val = get_floppy_geom(fd, capacity, &dkgeom);
3135		if (ret_val) {
3136			errno = ENOTSUP;
3137			return (-1);
3138		}
3139
3140	(void) memset((void *)&data, 0, sizeof (data));
3141	(void) memset((void *)&ucmd, 0, sizeof (ucmd));
3142	(void) memset((void *)&cdb, 0, sizeof (cdb));
3143
3144	/* retrieve size discriptor of inserted media */
3145	cdb[0] = SCMD_FORMAT;	/* format */
3146
3147	/*
3148	 * Defect list sent by initiator is a complete list of defects.
3149	 */
3150
3151	cdb[1] = (FMTDATA | 0x7);
3152
3153	cdb[8] = 0xC;   /* parameter list length */
3154	data[3] = 0x8;	/* should be always 8 */
3155
3156	data[4] = (uchar_t)(capacity >> 24);
3157	data[5] = (uchar_t)(capacity >> 16);
3158	data[6] = (uchar_t)(capacity >> 8);
3159	data[7] = (uchar_t)capacity;
3160
3161	data[9] = (uchar_t)(blocksize >> 16);
3162	data[10] = (uchar_t)(blocksize >> 8);
3163	data[11] = (uchar_t)blocksize;
3164
3165	ucmd.uscsi_cdb = (caddr_t)&cdb;
3166	ucmd.uscsi_cdblen = CDB_GROUP5;
3167	ucmd.uscsi_bufaddr = (caddr_t)data;
3168	ucmd.uscsi_buflen = sizeof (data);
3169	ucmd.uscsi_timeout = 0x15;
3170	ucmd.uscsi_rqlen = RQ_LEN;
3171	ucmd.uscsi_rqbuf = rq_data;
3172
3173	debug(5, "cdb: %x %x %x ... %x", cdb[0], cdb[1], cdb[2], cdb[8]);
3174	debug(5, "data: %x %x %x %x\n", data[0], data[1], data[2], data[3]);
3175	debug(5, "    : %x %x %x %x\n", data[4], data[5], data[6], data[7]);
3176	debug(5, "    : %x %x %x %x\n", data[8], data[9], data[10], data[11]);
3177
3178	for (i = 0; i < dkgeom.dkg_pcyl; i++) {	/* number of tracks */
3179		data[1] = (0xb0 | FOV);
3180		cdb[2] = i;
3181
3182		(void) fflush(stdout);
3183		ret_val = do_uscsi_cmd(fd, &ucmd, USCSI_WRITE|USCSI_RQENABLE);
3184		info("format side 0 returned : 0x%x\n", ret_val);
3185
3186		if (ret_val || ucmd.uscsi_status) {
3187			debug(5, "Retrieving media info failed: %d - %d\n",
3188			    ret_val, ucmd.uscsi_status);
3189			if ((rq_data[2] == KEY_DATA_PROTECT) &&
3190			    (rq_data[12] == 0x30) && (rq_data[13] == 0)) {
3191				debug(5, "Invalid command for media\n");
3192				errno = EINVAL;
3193			}
3194
3195			if ((rq_data[2] == KEY_NOT_READY) &&
3196			    (rq_data[12] == 0x30)) {
3197				debug(5, "Incompatible media.\n");
3198				errno = EINVAL;
3199			}
3200
3201			return (-1);
3202		}
3203		data[1] = (0xb0 | FOV) + 1;
3204		ret_val = do_uscsi_cmd(fd, &ucmd, USCSI_WRITE|USCSI_RQENABLE);
3205		info("format side 1 returned : 0x%x\n", ret_val);
3206
3207		if (ret_val || ucmd.uscsi_status) {
3208			debug(5, "Retrieving media info failed: %d - %d\n",
3209			    ret_val, ucmd.uscsi_status);
3210			if ((rq_data[2] == KEY_DATA_PROTECT) &&
3211			    (rq_data[12] == 0x30) && (rq_data[13] == 0)) {
3212				(void) info("Invalid command for media\n");
3213				errno = EINVAL;
3214			}
3215
3216			if ((rq_data[2] == KEY_NOT_READY) &&
3217			    (rq_data[12] == 0x30)) {
3218				debug(5, "Incompatible media.\n");
3219				errno = EINVAL;
3220			}
3221
3222			return (-1);
3223		}
3224	}
3225
3226	debug(5, "formatting done!");
3227	return (0);
3228}
3229
3230
3231/* ARGSUSED */
3232static int32_t
3233scsi_floppy_media_status(int32_t fd)
3234{
3235	struct mode_header_g1 modeh;
3236	struct uscsi_cmd ucmd;
3237	uchar_t cdb[10];
3238	int32_t ret_val;
3239	int32_t cur_status;
3240	char rq_data[RQ_LEN];
3241
3242	debug(5, "SCSI MEDIA STATUS CALLED \n");
3243
3244	(void) memset((void *) &modeh, 0, sizeof (modeh));
3245	(void) memset((void *) &ucmd, 0, sizeof (ucmd));
3246	(void) memset(cdb, 0, sizeof (cdb));
3247	/*
3248	 * issue 10 byte mode sense (0x5A)
3249	 */
3250	cdb[0] = SCMD_MODE_SENSE_G1;
3251	cdb[7] = sizeof (modeh) >> 8;
3252	cdb[8] = sizeof (modeh) & 0xff;
3253
3254	ucmd.uscsi_cdb = (caddr_t)cdb;
3255	ucmd.uscsi_cdblen = CDB_GROUP1;
3256	ucmd.uscsi_bufaddr = (caddr_t)&modeh;
3257	ucmd.uscsi_buflen = sizeof (modeh);
3258	ucmd.uscsi_timeout = 120;	/* If 0, HBA hangs forever */
3259	ucmd.uscsi_rqlen = RQ_LEN;
3260	ucmd.uscsi_rqbuf = rq_data;
3261	ret_val = do_uscsi_cmd(fd, &ucmd, USCSI_READ|USCSI_RQENABLE);
3262	if (ret_val || ucmd.uscsi_status) {
3263		/*
3264		 * UFI devices may not respond to the 0 mode page.
3265		 * retry with the error recovery page(0x01)
3266		 */
3267		if (ucmd.uscsi_status & STATUS_CHECK) {
3268			cdb[2] = 0x1;	/* page code */
3269			ret_val = do_uscsi_cmd(fd, &ucmd,
3270					USCSI_READ|USCSI_RQENABLE);
3271		}
3272		if (ret_val || ucmd.uscsi_status) {
3273			debug(1, "Modesense failed: %d - %d\n",
3274				ret_val, ucmd.uscsi_status);
3275			return (-1);
3276		}
3277	}
3278	debug(5, "Modesense succeeded: 0x%x\n", modeh.device_specific);
3279
3280	if (modeh.device_specific & 0x80) {
3281		cur_status = SM_WRITE_PROTECT_NOPASSWD;
3282	} else {
3283		cur_status = SM_WRITE_PROTECT_DISABLE;
3284	}
3285	return (cur_status);
3286}
3287