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