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