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