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