1/* 2 * Common functions for CAM "type" (peripheral) drivers. 3 * 4 * Copyright (c) 1997, 1998 Justin T. Gibbs. 5 * Copyright (c) 1997, 1998 Kenneth D. Merry. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without --- 12 unchanged lines hidden (view full) --- 21 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 * |
29 * $Id: cam_periph.c,v 1.6 1998/10/22 22:16:48 ken Exp $ |
30 */ 31 32#include <sys/param.h> 33#include <sys/systm.h> 34#include <sys/types.h> 35#include <sys/malloc.h> 36#include <sys/kernel.h> 37#include <sys/buf.h> --- 447 unchanged lines hidden (view full) --- 485 * access the memory. This won't work on physical pointers, for now it's 486 * up to the caller to check for that. (XXX KDM -- should we do that here 487 * instead?) This also only works for up to MAXPHYS memory. Since we use 488 * buffers to map stuff in and out, we're limited to the buffer size. 489 */ 490int 491cam_periph_mapmem(union ccb *ccb, struct cam_periph_map_info *mapinfo) 492{ |
493 int numbufs, i; 494 int flags[CAM_PERIPH_MAXMAPS]; |
495 u_int8_t **data_ptrs[CAM_PERIPH_MAXMAPS]; 496 u_int32_t lengths[CAM_PERIPH_MAXMAPS]; 497 u_int32_t dirs[CAM_PERIPH_MAXMAPS]; 498 499 switch(ccb->ccb_h.func_code) { 500 case XPT_DEV_MATCH: |
501 if (ccb->cdm.match_buf_len == 0) { 502 printf("cam_periph_mapmem: invalid match buffer " 503 "length 0\n"); 504 return(EINVAL); 505 } 506 if (ccb->cdm.pattern_buf_len > 0) { 507 data_ptrs[0] = (u_int8_t **)&ccb->cdm.patterns; 508 lengths[0] = ccb->cdm.pattern_buf_len; --- 5 unchanged lines hidden (view full) --- 514 } else { 515 data_ptrs[0] = (u_int8_t **)&ccb->cdm.matches; 516 lengths[0] = ccb->cdm.match_buf_len; 517 dirs[0] = CAM_DIR_IN; 518 numbufs = 1; 519 } 520 break; 521 case XPT_SCSI_IO: |
522 if ((ccb->ccb_h.flags & CAM_DIR_MASK) == CAM_DIR_NONE) 523 return(0); 524 525 data_ptrs[0] = &ccb->csio.data_ptr; |
526 lengths[0] = ccb->csio.dxfer_len; |
527 dirs[0] = ccb->ccb_h.flags & CAM_DIR_MASK; 528 numbufs = 1; 529 break; 530 default: 531 return(EINVAL); 532 break; /* NOTREACHED */ 533 } 534 |
535 /* |
536 * Check the transfer length and permissions first, so we don't 537 * have to unmap any previously mapped buffers. |
538 */ |
539 for (i = 0; i < numbufs; i++) { |
540 |
541 flags[i] = 0; 542 543 /* 544 * The userland data pointer passed in may not be page 545 * aligned. vmapbuf() truncates the address to a page 546 * boundary, so if the address isn't page aligned, we'll 547 * need enough space for the given transfer length, plus 548 * whatever extra space is necessary to make it to the page 549 * boundary. 550 */ 551 if ((lengths[i] + 552 (((vm_offset_t)(*data_ptrs[i])) & PAGE_MASK)) > MAXPHYS){ 553 printf("cam_periph_mapmem: attempt to map %u bytes, " 554 "which is greater than MAXPHYS(%d)\n", 555 lengths[i] + 556 (((vm_offset_t)(*data_ptrs[i])) & PAGE_MASK), 557 MAXPHYS); 558 return(E2BIG); 559 } 560 |
561 if (dirs[i] & CAM_DIR_IN) { |
562 flags[i] = B_READ; |
563 if (useracc(*data_ptrs[i], lengths[i], B_READ) == 0){ 564 printf("cam_periph_mapmem: error, " 565 "address %p, length %lu isn't " 566 "user accessible for READ\n", 567 (void *)*data_ptrs[i], 568 (u_long)lengths[i]); |
569 return(EACCES); 570 } 571 } 572 573 /* 574 * XXX this check is really bogus, since B_WRITE currently 575 * is all 0's, and so it is "set" all the time. 576 */ 577 if (dirs[i] & CAM_DIR_OUT) { |
578 flags[i] |= B_WRITE; |
579 if (useracc(*data_ptrs[i], lengths[i], B_WRITE) == 0){ 580 printf("cam_periph_mapmem: error, " 581 "address %p, length %lu isn't " 582 "user accessible for WRITE\n", 583 (void *)*data_ptrs[i], 584 (u_long)lengths[i]); |
585 586 return(EACCES); 587 } 588 } 589 |
590 } 591 592 /* this keeps the current process from getting swapped */ 593 /* 594 * XXX KDM should I use P_NOSWAP instead? 595 */ 596 curproc->p_flag |= P_PHYSIO; 597 598 for (i = 0; i < numbufs; i++) { |
599 /* 600 * Get the buffer. 601 */ 602 mapinfo->bp[i] = getpbuf(); 603 604 /* save the buffer's data address */ 605 mapinfo->bp[i]->b_saveaddr = mapinfo->bp[i]->b_data; 606 607 /* put our pointer in the data slot */ 608 mapinfo->bp[i]->b_data = *data_ptrs[i]; 609 |
610 /* set the transfer length, we know it's < MAXPHYS */ |
611 mapinfo->bp[i]->b_bufsize = lengths[i]; 612 613 /* set the flags */ |
614 mapinfo->bp[i]->b_flags = flags[i] | B_PHYS | B_BUSY; |
615 616 /* map the buffer into kernel memory */ 617 vmapbuf(mapinfo->bp[i]); 618 619 /* set our pointer to the new mapped area */ 620 *data_ptrs[i] = mapinfo->bp[i]->b_data; 621 622 mapinfo->num_bufs_used++; --- 937 unchanged lines hidden --- |