xref: /illumos-gate/usr/src/lib/libsmedia/plugins/scsi/common/s_generic.c (revision 45ede40b2394db7967e59f19288fae9b62efd4aa)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * s_generic.c :
29  *      This file contains generic SCSI related functions for scsi plug-in
30  * 	for libsm.so.
31  */
32 
33 
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <sys/ioctl.h>
37 #include <unistd.h>
38 #include <sys/shm.h>
39 #include <sys/mman.h>
40 #include <sys/smedia.h>
41 #include "../../../library/inc/rmedia.h"
42 #include <smserver.h>
43 #include <dirent.h>
44 #include <fcntl.h>
45 #include <sys/scsi/scsi.h>
46 #include <strings.h>
47 #include "../../../library/common/l_defines.h"
48 
49 
50 static int32_t remap_shared_buf(rmedia_handle_t *, size_t, char *);
51 
52 #define	W_E_MASK 0x80
53 #define	BUF_SIZE_MULTIPLE	0x2000
54 
55 int32_t
56 _m_get_media_info(rmedia_handle_t *handle, void *ip)
57 {
58 	smmedium_prop_t *medinfo = ip;
59 	int32_t ret_val;
60 	smedia_reqget_medium_property_t	reqget_medium_property;
61 	smedia_retget_medium_property_t	*retget_medium_property;
62 	smedia_reterror_t	*reterror;
63 	door_arg_t	door_args;
64 	char	rbuf[sizeof (smedia_services_t) + sizeof (door_desc_t)];
65 
66 	DPRINTF("get_media_info called.\n");
67 	/* Check for valid handle */
68 	if (handle == NULL) {
69 		DPRINTF("Null Handle\n");
70 		errno = EINVAL;
71 		return (-1);
72 	}
73 	if (handle->sm_signature != (int32_t)LIBSMEDIA_SIGNATURE) {
74 		DPRINTF("Invalid signature in handle.\n");
75 		DPRINTF2("Signature expected=0x%x, found=0x%x\n",
76 		    LIBSMEDIA_SIGNATURE, handle->sm_signature);
77 		DPRINTF1("fd=%d\n", handle->sm_fd);
78 		errno = EINVAL;
79 		return (-1);
80 	}
81 	(void) memset((void *) medinfo, 0, sizeof (smmedium_prop_t));
82 
83 	reqget_medium_property.cnum = SMEDIA_CNUM_GET_MEDIUM_PROPERTY;
84 	door_args.data_ptr = (char *)&reqget_medium_property;
85 	door_args.data_size = sizeof (smedia_services_t);
86 	door_args.desc_ptr = NULL;
87 	door_args.desc_num = 0;
88 	door_args.rbuf = rbuf;
89 	door_args.rsize = sizeof (rbuf);
90 
91 	ret_val = door_call(handle->sm_door, &door_args);
92 	if (ret_val < 0) {
93 		perror("door_call");
94 		return (-1);
95 	}
96 	retget_medium_property =
97 	    (smedia_retget_medium_property_t *)((void *)door_args.data_ptr);
98 	reterror = (smedia_reterror_t *)((void *)door_args.data_ptr);
99 	if (reterror->cnum == SMEDIA_CNUM_ERROR) {
100 		DPRINTF1(
101 	"Error in get_medium_property. errnum = 0x%x \n", reterror->errnum);
102 		errno = reterror->errnum;
103 		return (-1);
104 	}
105 
106 	*medinfo = retget_medium_property->smprop;
107 
108 	return (0);
109 }
110 
111 int32_t
112 _m_get_device_info(rmedia_handle_t *handle, void *ip)
113 {
114 	struct smdevice_info *dev_info = ip;
115 	int32_t	ret_val;
116 	smedia_reqget_device_info_t	reqget_device_info;
117 	smedia_retget_device_info_t	*retget_device_info;
118 	smedia_reterror_t	*reterror;
119 	door_arg_t	door_args;
120 	char	rbuf[sizeof (smedia_services_t) + sizeof (door_desc_t)];
121 	char *vendor_name, *product_name, *fw_version;
122 
123 	/* Check for valid handle */
124 	if (handle == NULL) {
125 		DPRINTF("Null Handle\n");
126 		errno = EINVAL;
127 		return (-1);
128 	}
129 	if (handle->sm_signature != LIBSMEDIA_SIGNATURE) {
130 		DPRINTF("Invalid signature in handle.\n");
131 		errno = EINVAL;
132 		return (-1);
133 	}
134 
135 	vendor_name = (char *)malloc(9);
136 	if (vendor_name == NULL) {
137 		if (!errno)
138 			errno = ENOMEM;
139 		return (-1);
140 	}
141 	product_name = (char *)malloc(17);
142 	if (product_name == NULL) {
143 		free(vendor_name);
144 		if (!errno)
145 			errno = ENOMEM;
146 		return (-1);
147 	}
148 
149 	fw_version = (char *)malloc(18);
150 	if (fw_version == NULL) {
151 		free(vendor_name);
152 		free(product_name);
153 		if (!errno)
154 			errno = ENOMEM;
155 		return (-1);
156 	}
157 	reqget_device_info.cnum = SMEDIA_CNUM_GET_DEVICE_INFO;
158 	door_args.data_ptr = (char *)&reqget_device_info;
159 	door_args.data_size = sizeof (smedia_services_t);
160 	door_args.desc_ptr = NULL;
161 	door_args.desc_num = 0;
162 	door_args.rbuf = rbuf;
163 	door_args.rsize = sizeof (rbuf);
164 
165 	ret_val = door_call(handle->sm_door, &door_args);
166 	if (ret_val < 0) {
167 		perror("door_call");
168 		free(vendor_name);
169 		free(product_name);
170 		free(fw_version);
171 		return (-1);
172 	}
173 	retget_device_info = (smedia_retget_device_info_t *)
174 	    ((void *)door_args.data_ptr);
175 	reterror = (smedia_reterror_t *)((void *)door_args.data_ptr);
176 	if (reterror->cnum == SMEDIA_CNUM_ERROR) {
177 		DPRINTF1("Error in get_device_info. errnum = 0x%x \n",
178 		    reterror->errnum);
179 		errno = reterror->errnum;
180 		free(vendor_name);
181 		free(product_name);
182 		free(fw_version);
183 		return (-1);
184 	}
185 
186 	dev_info->sm_vendor_name = vendor_name;
187 	dev_info->sm_product_name = product_name;
188 	dev_info->sm_firmware_version = fw_version;
189 
190 
191 	(void) strlcpy(dev_info->sm_vendor_name,
192 	    retget_device_info->sm_vendor_name, 8);
193 	dev_info->sm_vendor_name[8] = 0;
194 	(void) strlcpy(dev_info->sm_product_name,
195 	    retget_device_info->sm_product_name, 16);
196 	dev_info->sm_product_name[16] = 0;
197 	(void) strlcpy(dev_info->sm_firmware_version,
198 	    retget_device_info->sm_firmware_version, 17);
199 	dev_info->sm_firmware_version[17] = 0;
200 
201 	dev_info->sm_interface_type = retget_device_info->sm_interface_type;
202 
203 #ifdef DEBUG
204 	DPRINTF1("Vendor name = %s\n", dev_info->sm_vendor_name);
205 	DPRINTF1("product name = %s\n", dev_info->sm_product_name);
206 	DPRINTF1("Firmware revision = %s\n", dev_info->sm_firmware_version);
207 #endif /* DEBUG */
208 
209 	return (0);
210 }
211 
212 int32_t
213 _m_free_device_info(rmedia_handle_t *handle, void *ip)
214 {
215 	struct smdevice_info *dev_info = ip;
216 
217 	/* Check for valid handle */
218 	if (handle == NULL) {
219 		DPRINTF("Null Handle\n");
220 		errno = EINVAL;
221 		return (-1);
222 	}
223 	if (handle->sm_signature != LIBSMEDIA_SIGNATURE) {
224 		DPRINTF("Invalid signature in handle.\n");
225 		errno = EINVAL;
226 		return (-1);
227 	}
228 
229 	free(dev_info->sm_vendor_name);
230 	free(dev_info->sm_product_name);
231 	free(dev_info->sm_firmware_version);
232 	return (0);
233 }
234 
235 int32_t
236 _m_raw_write(rmedia_handle_t *handle, void *i_p)
237 {
238 	int32_t	ret_val;
239 	struct raw_params *r_p = (struct raw_params *)i_p;
240 	smedia_reqraw_write_t	reqraw_write;
241 	smedia_retraw_write_t	*retraw_write;
242 	smedia_reterror_t	*reterror;
243 	door_arg_t	door_args;
244 	char	rbuf[sizeof (smedia_services_t) + sizeof (door_desc_t)];
245 
246 	/* Check for valid handle */
247 	if (handle == NULL) {
248 		DPRINTF("Null Handle\n");
249 		errno = EINVAL;
250 		return (-1);
251 	}
252 	if (handle->sm_signature != LIBSMEDIA_SIGNATURE) {
253 		DPRINTF("Invalid signature in handle.\n");
254 		errno = EINVAL;
255 		return (-1);
256 	}
257 	(void) mutex_lock(&handle->sm_bufmutex);
258 	ret_val = remap_shared_buf(handle, r_p->size, r_p->buffer);
259 	if (ret_val != 0) goto error;
260 	reqraw_write.cnum = SMEDIA_CNUM_RAW_WRITE;
261 	reqraw_write.blockno = r_p->offset;
262 	reqraw_write.nbytes = r_p->size;
263 	bcopy(r_p->buffer, handle->sm_buf, r_p->size);
264 	door_args.data_ptr = (char *)&reqraw_write;
265 	door_args.data_size = sizeof (reqraw_write);
266 	door_args.desc_ptr = NULL;
267 	door_args.desc_num = 0;
268 	door_args.rbuf = rbuf;
269 	door_args.rsize = sizeof (rbuf);
270 
271 	ret_val = door_call(handle->sm_door, &door_args);
272 	if (ret_val < 0) {
273 		perror("door_call");
274 		goto error;
275 	}
276 	retraw_write = (smedia_retraw_write_t *)((void *)door_args.data_ptr);
277 	reterror = (smedia_reterror_t *)((void *)door_args.data_ptr);
278 	if (reterror->cnum == SMEDIA_CNUM_ERROR) {
279 		DPRINTF3("Error in raw write. errnum = 0x%x "
280 		    "blk_num = 0x%x(%d)\n", reterror->errnum, r_p->offset,
281 		    r_p->offset);
282 		errno = reterror->errnum;
283 		goto error;
284 	}
285 	(void) mutex_unlock(&handle->sm_bufmutex);
286 	return (retraw_write->nbytes);
287 
288 error:
289 	(void) mutex_unlock(&handle->sm_bufmutex);
290 	return (-1);
291 }
292 
293 size_t
294 _m_raw_read(rmedia_handle_t *handle, void *i_p)
295 {
296 	struct raw_params *r_p = (struct raw_params *)i_p;
297 	int32_t	ret_val, bytes_read;
298 	smedia_reqraw_read_t	reqraw_read;
299 	smedia_retraw_read_t	*retraw_read;
300 	smedia_reterror_t	*reterror;
301 	door_arg_t	door_args;
302 	char	rbuf[sizeof (smedia_services_t) + sizeof (door_desc_t)];
303 
304 	/* Check for valid handle */
305 	if (handle == NULL) {
306 		DPRINTF("Null Handle\n");
307 		errno = EINVAL;
308 		return (size_t)(-1);
309 	}
310 	if (handle->sm_signature != LIBSMEDIA_SIGNATURE) {
311 		DPRINTF("Invalid signature in handle.\n");
312 		return (size_t)(-1);
313 	}
314 	/*
315 	 * Check if another thread is doing an IO with same handle.
316 	 * In that case ww block here.
317 	 */
318 	(void) mutex_lock(&handle->sm_bufmutex);
319 	ret_val = remap_shared_buf(handle, r_p->size, r_p->buffer);
320 	if (ret_val != 0) goto error;
321 
322 	reqraw_read.cnum = SMEDIA_CNUM_RAW_READ;
323 	reqraw_read.blockno = r_p->offset;
324 	reqraw_read.nbytes = r_p->size;
325 	door_args.data_ptr = (char *)&reqraw_read;
326 	door_args.data_size = sizeof (smedia_services_t);
327 	door_args.desc_ptr = NULL;
328 	door_args.desc_num = 0;
329 	door_args.rbuf = rbuf;
330 	door_args.rsize = sizeof (rbuf);
331 
332 	ret_val = door_call(handle->sm_door, &door_args);
333 	if (ret_val < 0) {
334 		perror("door_call");
335 		goto error;
336 	}
337 	retraw_read = (smedia_retraw_read_t *)((void *)door_args.data_ptr);
338 	reterror = (smedia_reterror_t *)((void *)door_args.data_ptr);
339 	if (reterror->cnum == SMEDIA_CNUM_ERROR) {
340 		/*
341 		 * free(rbuf);
342 		 */
343 		DPRINTF3("Error in raw read. errnum = 0x%x "
344 		    "blk_num = 0x%x(%d)\n", reterror->errnum, r_p->offset,
345 		    r_p->offset);
346 		errno = reterror->errnum;
347 		goto error;
348 	}
349 	(void) memcpy(r_p->buffer, handle->sm_buf, retraw_read->nbytes);
350 	bytes_read = retraw_read->nbytes;
351 	(void) mutex_unlock(&handle->sm_bufmutex);
352 	return (bytes_read);
353 
354 error:
355 	(void) mutex_unlock(&handle->sm_bufmutex);
356 	return (size_t)(-1);
357 
358 }
359 
360 size_t
361 _m_media_format(rmedia_handle_t *handle, void *ip)
362 {
363 	int32_t ret_val;
364 	struct format_flags *ffl = (struct format_flags *)ip;
365 	smedia_reqformat_t	reqformat;
366 	smedia_reterror_t	*reterror;
367 	door_arg_t	door_args;
368 	char	rbuf[sizeof (smedia_services_t) + sizeof (door_desc_t)];
369 
370 	/* Check for valid handle */
371 	if (handle == NULL) {
372 		DPRINTF("Null Handle\n");
373 		errno = EINVAL;
374 		return (size_t)(-1);
375 	}
376 	if (handle->sm_signature != LIBSMEDIA_SIGNATURE) {
377 		DPRINTF("Invalid signature in handle.\n");
378 		errno = EINVAL;
379 		return (size_t)(-1);
380 	}
381 	reqformat.cnum = SMEDIA_CNUM_FORMAT;
382 	reqformat.flavor = ffl->flavor;
383 	reqformat.mode = ffl->mode;
384 	door_args.data_ptr = (char *)&reqformat;
385 	door_args.data_size = sizeof (smedia_services_t);
386 	door_args.desc_ptr = NULL;
387 	door_args.desc_num = 0;
388 	door_args.rbuf = rbuf;
389 	door_args.rsize = sizeof (rbuf);
390 
391 	ret_val = door_call(handle->sm_door, &door_args);
392 	if (ret_val < 0) {
393 		perror("door_call");
394 		return (size_t)(-1);
395 	}
396 	reterror = (smedia_reterror_t *)((void *)door_args.data_ptr);
397 	if (reterror->cnum == SMEDIA_CNUM_ERROR) {
398 		DPRINTF1("Error in format. errnum = 0x%x \n", reterror->errnum);
399 		errno = reterror->errnum;
400 		return (size_t)(-1);
401 	}
402 	return (0);
403 }
404 
405 int32_t
406 _m_get_media_status(rmedia_handle_t *handle, void *ip)
407 {
408 	smwp_state_t	*wp = ip;
409 	int32_t ret_val;
410 	smedia_reqget_protection_status_t	reqget_protection_status;
411 	smedia_retget_protection_status_t	*retget_protection_status;
412 	smedia_reterror_t	*reterror;
413 	door_arg_t	door_args;
414 	char	rbuf[sizeof (smedia_services_t) + sizeof (door_desc_t)];
415 
416 	/* Check for valid handle */
417 	if (handle == NULL) {
418 		DPRINTF("Null Handle\n");
419 		errno = EINVAL;
420 		return (-1);
421 	}
422 	if (handle->sm_signature != LIBSMEDIA_SIGNATURE) {
423 		DPRINTF("Invalid signature in handle.\n");
424 		errno = EINVAL;
425 		return (-1);
426 	}
427 	reqget_protection_status.cnum = SMEDIA_CNUM_GET_PROTECTION_STATUS;
428 	door_args.data_ptr = (char *)&reqget_protection_status;
429 	door_args.data_size = sizeof (smedia_services_t);
430 	door_args.desc_ptr = NULL;
431 	door_args.desc_num = 0;
432 	door_args.rbuf = rbuf;
433 	door_args.rsize = sizeof (rbuf);
434 
435 	ret_val = door_call(handle->sm_door, &door_args);
436 	if (ret_val < 0) {
437 		perror("door_call");
438 		return (-1);
439 	}
440 	retget_protection_status = (smedia_retget_protection_status_t *)
441 	    ((void *)door_args.data_ptr);
442 	reterror = (smedia_reterror_t *)((void *)door_args.data_ptr);
443 	if (reterror->cnum == SMEDIA_CNUM_ERROR) {
444 		DPRINTF1("Error in get_protection-status. errnum = 0x%x \n",
445 		    reterror->errnum);
446 		errno = reterror->errnum;
447 		return (-1);
448 	}
449 	(void) memcpy((char *)wp, (char *)&retget_protection_status->prot_state,
450 	    sizeof (smwp_state_t));
451 	return (0);
452 }
453 
454 int32_t
455 _m_set_media_status(rmedia_handle_t *handle, void *ip)
456 {
457 
458 	smwp_state_t	*wp = ip;
459 	int32_t ret_val;
460 	smedia_reqset_protection_status_t	reqset_protection_status;
461 	smedia_reterror_t	*reterror;
462 	door_arg_t	door_args;
463 	char	rbuf[sizeof (smedia_services_t) + sizeof (door_desc_t)];
464 
465 	/* Check for valid handle */
466 	if (handle == NULL) {
467 		DPRINTF("Null Handle\n");
468 		errno = EINVAL;
469 		return (-1);
470 	}
471 	if (handle->sm_signature != LIBSMEDIA_SIGNATURE) {
472 		DPRINTF("Invalid signature in handle.\n");
473 		errno = EINVAL;
474 		return (-1);
475 	}
476 	reqset_protection_status.cnum = SMEDIA_CNUM_SET_PROTECTION_STATUS;
477 	reqset_protection_status.prot_state = *wp;
478 	door_args.data_ptr = (char *)&reqset_protection_status;
479 	door_args.data_size = sizeof (smedia_services_t);
480 	door_args.desc_ptr = NULL;
481 	door_args.desc_num = 0;
482 	door_args.rbuf = rbuf;
483 	door_args.rsize = sizeof (rbuf);
484 
485 	ret_val = door_call(handle->sm_door, &door_args);
486 	if (ret_val < 0) {
487 		perror("door_call");
488 		return (-1);
489 	}
490 	reterror = (smedia_reterror_t *)((void *)door_args.data_ptr);
491 	if (reterror->cnum == SMEDIA_CNUM_ERROR) {
492 		DPRINTF1(
493 	"Error in set_protection-status. errnum = 0x%x \n", reterror->errnum);
494 		errno = reterror->errnum;
495 		return (-1);
496 	}
497 	return (0);
498 }
499 
500 int32_t
501 _m_reassign_block(rmedia_handle_t *handle, void *ip)
502 {
503 	uint32_t block;
504 	diskaddr_t *blockp  = (diskaddr_t *)ip;
505 	int32_t	ret_val;
506 	smedia_reqreassign_block_t	reqreassign_block;
507 	smedia_reterror_t		*reterror;
508 	door_arg_t	door_args;
509 	char	rbuf[sizeof (smedia_services_t) + sizeof (door_desc_t)];
510 
511 	/* Check for valid handle */
512 	if (handle == NULL) {
513 		DPRINTF("Null Handle\n");
514 		errno = EINVAL;
515 		return (-1);
516 	}
517 	if (handle->sm_signature != LIBSMEDIA_SIGNATURE) {
518 		DPRINTF("Invalid signature in handle.\n");
519 		errno = EINVAL;
520 		return (-1);
521 	}
522 	block = *blockp;
523 	DPRINTF1("reassign block %d\n", block);
524 	reqreassign_block.cnum = SMEDIA_CNUM_REASSIGN_BLOCK;
525 	reqreassign_block.blockno = block;
526 	door_args.data_ptr = (char *)&reqreassign_block;
527 	door_args.data_size = sizeof (smedia_services_t);
528 	door_args.desc_ptr = NULL;
529 	door_args.desc_num = 0;
530 	door_args.rbuf = rbuf;
531 	door_args.rsize = sizeof (rbuf);
532 
533 	ret_val = door_call(handle->sm_door, &door_args);
534 	if (ret_val < 0) {
535 		perror("door_call");
536 		return (-1);
537 	}
538 	reterror = (smedia_reterror_t *)((void *)door_args.data_ptr);
539 	if (reterror->cnum == SMEDIA_CNUM_ERROR) {
540 		DPRINTF2("Error in reassign_block. block = 0x%x "
541 		    "errnum = 0x%x \n", block, reterror->errnum);
542 		errno = reterror->errnum;
543 		return (-1);
544 	}
545 	return (0);
546 }
547 
548 /* ARGSUSED1 */
549 int32_t
550 _m_eject(rmedia_handle_t *handle, void *ip)
551 {
552 	int32_t	fd;
553 
554 	/* Check for valid handle */
555 	if (handle == NULL) {
556 		DPRINTF("Null Handle\n");
557 		errno = EINVAL;
558 		return (-1);
559 	}
560 	if (handle->sm_signature != LIBSMEDIA_SIGNATURE) {
561 		DPRINTF("Invalid signature in handle.\n");
562 		errno = EINVAL;
563 		return (-1);
564 	}
565 	fd = handle->sm_fd;
566 	return (ioctl(fd, DKIOCEJECT));
567 }
568 
569 int32_t
570 _m_device_type(ushort_t ctype, ushort_t mtype)
571 {
572 	if ((ctype == DKC_SCSI_CCS) ||
573 	    (ctype == DKC_MD21) ||
574 	    (ctype == DKC_CDROM)) {
575 		if (mtype == 0)
576 			return (0);
577 	}
578 	return (-1);
579 }
580 
581 int32_t
582 _m_version_no(void)
583 {
584 	return (SM_SCSI_VERSION_1);
585 }
586 
587 int32_t
588 _m_check_format_status(rmedia_handle_t *handle, void *ip)
589 {
590 	int32_t ret_val;
591 	smedia_reqcheck_format_status_t	reqcheck_format_status;
592 	smedia_retcheck_format_status_t	*retcheck_format_status;
593 	smedia_reterror_t	*reterror;
594 	door_arg_t	door_args;
595 	char	rbuf[sizeof (smedia_services_t) + sizeof (door_desc_t)];
596 #ifdef	lint
597 	ip = ip;
598 #endif
599 
600 	/* Check for valid handle */
601 	if (handle == NULL) {
602 		DPRINTF("Null Handle\n");
603 		errno = EINVAL;
604 		return (-1);
605 	}
606 	if (handle->sm_signature != LIBSMEDIA_SIGNATURE) {
607 		DPRINTF("Invalid signature in handle.\n");
608 		errno = EINVAL;
609 		return (-1);
610 	}
611 	reqcheck_format_status.cnum = SMEDIA_CNUM_CHECK_FORMAT_STATUS;
612 	door_args.data_ptr = (char *)&reqcheck_format_status;
613 	door_args.data_size = sizeof (smedia_services_t);
614 	door_args.desc_ptr = NULL;
615 	door_args.desc_num = 0;
616 	door_args.rbuf = rbuf;
617 	door_args.rsize = sizeof (rbuf);
618 
619 	ret_val = door_call(handle->sm_door, &door_args);
620 	if (ret_val < 0) {
621 		perror("door_call");
622 		return (-1);
623 	}
624 	retcheck_format_status =
625 	    (smedia_retcheck_format_status_t *)((void *)door_args.data_ptr);
626 	reterror = (smedia_reterror_t *)((void *)door_args.data_ptr);
627 	if (reterror->cnum == SMEDIA_CNUM_ERROR) {
628 		DPRINTF1("Error in check_format_status. errnum = 0x%x \n",
629 		    reterror->errnum);
630 		errno = reterror->errnum;
631 		return (-1);
632 	}
633 	return (retcheck_format_status->percent_complete);
634 }
635 
636 int32_t
637 _m_uscsi_cmd(rmedia_handle_t *handle, struct uscsi_cmd *ucmd)
638 {
639 	int32_t	ret_val;
640 	smedia_requscsi_cmd_t	requscsi_cmd;
641 	smedia_retuscsi_cmd_t	*retuscsi_cmd;
642 	smedia_reterror_t	*reterror;
643 	door_arg_t	door_args;
644 	char	rbuf[sizeof (smedia_services_t) + sizeof (door_desc_t)];
645 
646 	/* Check for valid handle */
647 	if (handle == NULL) {
648 		DPRINTF("Null Handle\n");
649 		errno = EINVAL;
650 		return (-1);
651 	}
652 	if (handle->sm_signature != LIBSMEDIA_SIGNATURE) {
653 		DPRINTF("Invalid signature in handle.\n");
654 		errno = EINVAL;
655 		return (-1);
656 	}
657 	/*
658 	 * We will be validating the user supplied buffer lengths and
659 	 * buffer pointers.
660 	 */
661 	if (ucmd->uscsi_cdblen > MAX_CDB_LEN) {
662 		DPRINTF("Invalid cdblen specified.\n");
663 		errno = EINVAL;
664 		return (-1);
665 	}
666 	if ((ucmd->uscsi_flags & USCSI_RQENABLE) &&
667 	    (ucmd->uscsi_rqlen > MAX_RQ_LEN)) {
668 		DPRINTF("Invalid rqlen specified.\n");
669 		errno = EINVAL;
670 		return (-1);
671 	}
672 	if (ucmd->uscsi_cdb == NULL) {
673 		DPRINTF("cdb buffer is NULL.\n");
674 		errno = EINVAL;
675 		return (-1);
676 	}
677 	if ((ucmd->uscsi_buflen) && (ucmd->uscsi_bufaddr == NULL)) {
678 		DPRINTF("bufaddr is NULL.\n");
679 		errno = EINVAL;
680 		return (-1);
681 	}
682 	if ((ucmd->uscsi_flags & USCSI_RQENABLE) &&
683 	    (ucmd->uscsi_rqbuf == NULL)) {
684 		DPRINTF("rqbuf is NULL.\n");
685 		errno = EINVAL;
686 		return (-1);
687 	}
688 	/*
689 	 * Check if another thread is doing an IO with same handle.
690 	 * In that case we block here.
691 	 */
692 	(void) mutex_lock(&handle->sm_bufmutex);
693 	ret_val = remap_shared_buf(handle, ucmd->uscsi_buflen,
694 	    ucmd->uscsi_bufaddr);
695 	if (ret_val != 0) {
696 		DPRINTF("remap of shared buf failed.\n");
697 		goto error;
698 	}
699 
700 	requscsi_cmd.cnum = SMEDIA_CNUM_USCSI_CMD;
701 	requscsi_cmd.uscsi_flags = ucmd->uscsi_flags;
702 	requscsi_cmd.uscsi_timeout = ucmd->uscsi_timeout;
703 	requscsi_cmd.uscsi_buflen = ucmd->uscsi_buflen;
704 	requscsi_cmd.uscsi_cdblen = ucmd->uscsi_cdblen;
705 	requscsi_cmd.uscsi_rqlen = ucmd->uscsi_rqlen;
706 
707 	/*
708 	 * The uscsi_buflen has been validated in the call to
709 	 * remap_shared_buf() done earlier.
710 	 */
711 	/* Check for write */
712 	if (!(ucmd->uscsi_flags & USCSI_READ)) {
713 		bcopy(ucmd->uscsi_bufaddr, handle->sm_buf, ucmd->uscsi_buflen);
714 	}
715 
716 	bcopy(ucmd->uscsi_cdb, requscsi_cmd.uscsi_cdb, ucmd->uscsi_cdblen);
717 
718 	door_args.data_ptr = (char *)&requscsi_cmd;
719 	door_args.data_size = sizeof (smedia_services_t);
720 	door_args.desc_ptr = NULL;
721 	door_args.desc_num = 0;
722 	door_args.rbuf = rbuf;
723 	door_args.rsize = sizeof (rbuf);
724 
725 	ret_val = door_call(handle->sm_door, &door_args);
726 	if (ret_val < 0) {
727 		perror("door_call");
728 		goto error;
729 	}
730 	retuscsi_cmd = (smedia_retuscsi_cmd_t *)((void *)door_args.data_ptr);
731 	reterror = (smedia_reterror_t *)((void *)door_args.data_ptr);
732 	if (reterror->cnum == SMEDIA_CNUM_ERROR) {
733 		DPRINTF1(
734 		"Error in uscsi cmd. errnum = 0x%x\n", reterror->errnum);
735 		errno = reterror->errnum;
736 		goto error;
737 	}
738 	ucmd->uscsi_status = retuscsi_cmd->uscsi_status;
739 	ucmd->uscsi_resid = retuscsi_cmd->uscsi_resid;
740 	ucmd->uscsi_rqstatus = retuscsi_cmd->uscsi_rqstatus;
741 	ucmd->uscsi_rqresid = retuscsi_cmd->uscsi_rqresid;
742 	if ((ucmd->uscsi_flags & USCSI_RQENABLE) &&
743 	    (ucmd->uscsi_rqbuf != NULL)) {
744 		bcopy(retuscsi_cmd->uscsi_rqbuf, ucmd->uscsi_rqbuf,
745 		    ucmd->uscsi_rqlen);
746 	}
747 	errno = retuscsi_cmd->uscsi_errno;
748 	if (errno) {
749 		goto error;
750 	}
751 
752 	if (ucmd->uscsi_resid > ucmd->uscsi_buflen) {
753 		/*
754 		 * Invalid resid value. return error.
755 		 */
756 		errno = EINVAL;
757 		goto error;
758 	}
759 	if (ucmd->uscsi_flags & USCSI_READ) {
760 		(void) memcpy(ucmd->uscsi_bufaddr,
761 		    handle->sm_buf, ucmd->uscsi_buflen - ucmd->uscsi_resid);
762 	}
763 	(void) mutex_unlock(&handle->sm_bufmutex);
764 #ifdef DEBUG
765 	if (retuscsi_cmd->uscsi_retval || ucmd->uscsi_status)
766 		DPRINTF2("Error in uscsi_cmd: retval=0x%x uscsi_status=0x%x\n",
767 		    retuscsi_cmd->uscsi_retval, ucmd->uscsi_status);
768 #endif
769 	return (retuscsi_cmd->uscsi_retval);
770 error:
771 	(void) mutex_unlock(&handle->sm_bufmutex);
772 	return (-1);
773 }
774 
775 int32_t
776 remap_shared_buf(rmedia_handle_t *handle, size_t buf_size, char *buffer)
777 {
778 	char	rbuf[sizeof (smedia_services_t) + sizeof (door_desc_t)];
779 	char	fname[128];
780 	smedia_reqset_shfd_t	reqset_shfd;
781 	smedia_reterror_t	*reterror;
782 	int	ret_val, fd;
783 	door_arg_t	door_args;
784 	door_desc_t	ddesc[2];
785 	char	*fbuf;
786 	size_t	shared_bufsize;
787 	off_t	file_size, ret;
788 
789 	if (handle->sm_bufsize >= buf_size)
790 		return (0);
791 	shared_bufsize = ((buf_size + BUF_SIZE_MULTIPLE - 1)/BUF_SIZE_MULTIPLE)
792 	    * BUF_SIZE_MULTIPLE;
793 	if (handle->sm_buffd != -1) {
794 		/* extend the file and re-map */
795 		fd = handle->sm_buffd;
796 		ret_val = munmap(handle->sm_buf, handle->sm_bufsize);
797 		if (ret_val != 0) {
798 			DPRINTF1("remap:munmap failed. errno = 0x%x\n", errno);
799 			(void) close(fd);
800 			handle->sm_buf = NULL;
801 			handle->sm_bufsize = 0;
802 			handle->sm_buffd = -1;
803 			return (errno);
804 		}
805 		file_size = lseek(fd, 0, SEEK_END);
806 		if (file_size == -1) {
807 			DPRINTF1("remap:lseek failed. errno = 0x%x\n", errno);
808 			return (errno);
809 		}
810 		handle->sm_buf = NULL;
811 		handle->sm_bufsize = 0;
812 		handle->sm_buffd = -1;
813 	} else {
814 		/* create a new file and mapping */
815 		(void) sprintf(fname, "/tmp/libsmedia_mmaped_file_XXXXXX");
816 		fd = mkstemp(fname);
817 		if (fd == -1) {
818 			DPRINTF1("remap:mktemp failed. errno = 0x%x\n", errno);
819 			return (errno);
820 		}
821 		ret_val = unlink(fname);
822 		if (ret_val == -1) {
823 			DPRINTF1("remap:unlink failed. errno = 0x%x\n", errno);
824 			(void) close(fd);
825 			return (errno);
826 		}
827 		file_size = 0;
828 	}
829 	/* Need to start at the beginning of the file when enlarging */
830 	ret = lseek(fd, 0, SEEK_SET);
831 	if (ret == -1) {
832 		DPRINTF1("remap:lseek failed. errno = 0x%x\n", errno);
833 		return (errno);
834 	}
835 	while (file_size < shared_bufsize) {
836 		ret_val = write(fd, buffer, buf_size);
837 		if (ret_val != buf_size) {
838 			DPRINTF1("remap:write failed. errno = 0x%x\n", errno);
839 			(void) close(fd);
840 			return (errno);
841 		}
842 		file_size += buf_size;
843 	}
844 	fbuf = mmap(NULL, shared_bufsize, PROT_READ | PROT_WRITE,
845 	    MAP_SHARED, fd, 0);
846 	if (fbuf == (char *)-1) {
847 		perror("mmap failed");
848 		(void) close(fd);
849 		return (errno);
850 	}
851 
852 	reqset_shfd.cnum = SMEDIA_CNUM_SET_SHFD;
853 	reqset_shfd.fdbuf_len = shared_bufsize;
854 	ddesc[0].d_data.d_desc.d_descriptor = fd;
855 	ddesc[0].d_attributes = DOOR_DESCRIPTOR;
856 	door_args.data_ptr = (char *)&reqset_shfd;
857 	door_args.data_size = sizeof (reqset_shfd);
858 	door_args.desc_ptr = &ddesc[0];
859 	door_args.desc_num = 1;
860 	door_args.rbuf = rbuf;
861 	door_args.rsize = sizeof (rbuf);
862 
863 	ret_val = door_call(handle->sm_door, &door_args);
864 	if (ret_val < 0) {
865 		perror("door_call");
866 		(void) close(fd);
867 		return (-1);
868 	}
869 	reterror = (smedia_reterror_t *)((void *)door_args.data_ptr);
870 	if (reterror->cnum == SMEDIA_CNUM_ERROR) {
871 		DPRINTF1("Error in set shfd. errnum = 0x%x\n",
872 		    reterror->errnum);
873 		errno = reterror->errnum;
874 		(void) close(fd);
875 		return (errno);
876 	}
877 	handle->sm_buffd = fd;
878 	handle->sm_buf = fbuf;
879 	handle->sm_bufsize = shared_bufsize;
880 	DPRINTF("Returned successful from remap shared buf routine.\n");
881 	return (0);
882 }
883