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  * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 /*
26  *
27  * Generic Capabilities Routines
28  *
29  */
30 
31 #include <sys/scsi/scsi.h>
32 #ifdef	__x86
33 #include <sys/ddi_isa.h>
34 #endif
35 
36 #define	A_TO_TRAN(ap)	(ap->a_hba_tran)
37 
38 
39 int
scsi_ifgetcap(struct scsi_address * ap,char * cap,int whom)40 scsi_ifgetcap(struct scsi_address *ap, char *cap, int whom)
41 {
42 	int capability;
43 #ifdef	__x86
44 	ddi_dma_attr_t *dmaattr;
45 	int ckey;
46 #endif
47 
48 
49 	capability = (*A_TO_TRAN(ap)->tran_getcap)(ap, cap, whom);
50 
51 #ifdef	__x86
52 	if (cap != NULL) {
53 		ckey = scsi_hba_lookup_capstr(cap);
54 		dmaattr = &ap->a_hba_tran->tran_dma_attr;
55 		switch (ckey) {
56 		case SCSI_CAP_DMA_MAX:
57 			/*
58 			 * If the HBA is unable to reach all the memory in
59 			 * the system, the maximum copy buffer size may limit
60 			 * the size of the max DMA.
61 			 */
62 			if (i_ddi_copybuf_required(dmaattr)) {
63 				capability = MIN(capability,
64 				    i_ddi_copybuf_size());
65 			}
66 
67 			/*
68 			 * make sure the value we return is a whole multiple of
69 			 * the granlarity.
70 			 */
71 			if (dmaattr->dma_attr_granular > 1) {
72 				capability = capability -
73 				    (capability % dmaattr->dma_attr_granular);
74 			}
75 
76 			break;
77 
78 		case SCSI_CAP_DMA_MAX_ARCH:
79 			capability = i_ddi_dma_max(ap->a_hba_tran->tran_hba_dip,
80 			    dmaattr);
81 
82 			break;
83 
84 		/*FALLTHROUGH*/
85 		}
86 	}
87 #endif
88 
89 	return (capability);
90 }
91 
92 int
scsi_ifsetcap(struct scsi_address * ap,char * cap,int value,int whom)93 scsi_ifsetcap(struct scsi_address *ap, char *cap, int value, int whom)
94 {
95 	int rval;
96 	int cidx;
97 
98 	rval = (*A_TO_TRAN(ap)->tran_setcap)(ap, cap, value, whom);
99 	if ((rval == 1) || A_TO_TRAN(ap)->tran_setup_pkt) {
100 		cidx = scsi_hba_lookup_capstr(cap);
101 		if (cidx == SCSI_CAP_SECTOR_SIZE) {
102 			/*
103 			 * if we have successfully changed the
104 			 * granularity update SCSA's copy
105 			 */
106 			A_TO_TRAN(ap)->tran_dma_attr.dma_attr_granular =
107 			    value;
108 		}
109 	}
110 	return (rval);
111 }
112