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