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