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
39int
40scsi_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
92int
93scsi_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