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