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