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