xref: /illumos-gate/usr/src/uts/common/io/sdcard/impl/sda_mem.c (revision 2e0fe3efe5f9d579d4e44b3532d8e342c68b40ca)
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) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 /*
26  * Memory target support for SDcard.
27  */
28 
29 #include <sys/types.h>
30 #include <sys/note.h>
31 #include <sys/conf.h>
32 #include <sys/blkdev.h>
33 #include <sys/ddi.h>
34 #include <sys/sunddi.h>
35 #include <sys/sdcard/sda.h>
36 #include <sys/sdcard/sda_impl.h>
37 
38 static int sda_mem_errno(sda_err_t);
39 static int sda_mem_rw(sda_slot_t *, bd_xfer_t *, uint8_t, uint16_t);
40 static void sda_mem_done(sda_cmd_t *);
41 static void sda_mem_getstring(uint32_t *, char *, int, int);
42 
43 /*
44  * To minimize complexity and reduce layering, we implement almost the
45  * entire memory card driver (sdcard) here.  The memory card still
46  * needs to be a separate driver though, due to the requirement to
47  * have both SCSI HBA bus ops and SD bus ops.
48  */
49 
50 /*
51  * Everything beyond this is private.
52  */
53 
54 int
55 sda_mem_errno(sda_err_t errno)
56 {
57 	/* the hot path */
58 	if (errno == SDA_EOK) {
59 		return (0);
60 	}
61 
62 	switch (errno) {
63 	case SDA_ENOMEM:
64 		return (ENOMEM);
65 	case SDA_ETIME:
66 		return (ETIMEDOUT);
67 	case SDA_EWPROTECT:
68 		return (EROFS);
69 	case SDA_ESUSPENDED:
70 	case SDA_ENODEV:
71 		return (ENODEV);
72 	case SDA_EFAULT:
73 	case SDA_ECRC7:
74 	case SDA_EPROTO:
75 	case SDA_ERESET:
76 	case SDA_EIO:
77 	case SDA_ERESID:
78 	default:
79 		return (EIO);
80 	}
81 }
82 
83 void
84 sda_mem_done(sda_cmd_t *cmdp)
85 {
86 	bd_xfer_t	*xfer = sda_cmd_data(cmdp);
87 	int		errno = sda_cmd_errno(cmdp);
88 
89 	bd_xfer_done(xfer, sda_mem_errno(errno));
90 	sda_cmd_free(cmdp);
91 }
92 
93 int
94 sda_mem_rw(sda_slot_t *slot, bd_xfer_t *xfer, uint8_t cmd, uint16_t flags)
95 {
96 	sda_cmd_t	*cmdp;
97 	uint64_t	nblks;
98 	uint64_t	blkno;
99 	uint16_t	rblen;
100 
101 	blkno = xfer->x_blkno;
102 	nblks = xfer->x_nblks;
103 
104 	ASSERT(nblks != 0);
105 
106 	if ((blkno + nblks) > slot->s_nblks) {
107 		return (EINVAL);
108 	}
109 
110 	cmdp = sda_cmd_alloc(slot, cmd, blkno << slot->s_bshift,
111 	    R1, xfer, KM_NOSLEEP);
112 	if (cmdp == NULL) {
113 		return (ENOMEM);
114 	}
115 
116 	if (slot->s_hostp->h_dma != NULL) {
117 		cmdp->sc_dmah = xfer->x_dmah;
118 		cmdp->sc_ndmac = xfer->x_ndmac;
119 		cmdp->sc_dmac = xfer->x_dmac;
120 		cmdp->sc_kvaddr = 0;
121 	} else {
122 		cmdp->sc_ndmac = 0;
123 		cmdp->sc_kvaddr = xfer->x_kaddr;
124 	}
125 
126 	rblen = slot->s_blksz;
127 
128 	/* other fields are set by sda_cmd_alloc */
129 	cmdp->sc_blksz = rblen;
130 	cmdp->sc_nblks = (uint16_t)nblks;
131 	cmdp->sc_flags = flags;
132 
133 	sda_cmd_submit(slot, cmdp, sda_mem_done);
134 	return (0);
135 }
136 
137 int
138 sda_mem_bd_read(void *arg, bd_xfer_t *xfer)
139 {
140 	sda_slot_t	*slot = arg;
141 	uint8_t		cmd;
142 	uint16_t	flags;
143 
144 	if (xfer->x_nblks > 1) {
145 		cmd = CMD_READ_MULTI;
146 		flags = SDA_CMDF_DAT | SDA_CMDF_MEM | SDA_CMDF_READ |
147 		    SDA_CMDF_AUTO_CMD12;
148 	} else {
149 		cmd = CMD_READ_SINGLE;
150 		flags = SDA_CMDF_DAT | SDA_CMDF_MEM | SDA_CMDF_READ;
151 	}
152 
153 	return (sda_mem_rw(slot, xfer, cmd, flags));
154 }
155 
156 int
157 sda_mem_bd_write(void *arg, bd_xfer_t *xfer)
158 {
159 	sda_slot_t	*slot = arg;
160 	uint8_t		cmd;
161 	uint16_t	flags;
162 
163 	if ((slot->s_flags & SLOTF_WRITABLE) == 0) {
164 		return (EROFS);
165 	}
166 	if (xfer->x_nblks > 1) {
167 		cmd = CMD_WRITE_MULTI;
168 		flags = SDA_CMDF_DAT | SDA_CMDF_MEM | SDA_CMDF_WRITE |
169 		    SDA_CMDF_AUTO_CMD12;
170 	} else {
171 		cmd = CMD_WRITE_SINGLE;
172 		flags = SDA_CMDF_DAT | SDA_CMDF_MEM | SDA_CMDF_WRITE;
173 	}
174 
175 	return (sda_mem_rw(slot, xfer, cmd, flags));
176 }
177 
178 void
179 sda_mem_bd_driveinfo(void *arg, bd_drive_t *drive)
180 {
181 	sda_slot_t	*slot = arg;
182 
183 	drive->d_qsize = 4;	/* we queue up internally, 4 is enough */
184 	drive->d_maxxfer = 65536;
185 	drive->d_removable = B_TRUE;
186 	drive->d_hotpluggable = B_FALSE;
187 	drive->d_target = slot->s_slot_num;
188 }
189 
190 int
191 sda_mem_bd_mediainfo(void *arg, bd_media_t *media)
192 {
193 	sda_slot_t	*slot = arg;
194 
195 	sda_slot_enter(slot);
196 	if (!slot->s_ready) {
197 		sda_slot_exit(slot);
198 		return (ENXIO);
199 	}
200 	media->m_nblks = slot->s_nblks;
201 	media->m_blksize = slot->s_blksz;
202 	media->m_readonly = slot->s_flags & SLOTF_WRITABLE ? B_FALSE : B_TRUE;
203 	sda_slot_exit(slot);
204 	return (0);
205 }
206 
207 uint32_t
208 sda_mem_getbits(uint32_t *resp, int hibit, int len)
209 {
210 	uint32_t	val = 0;
211 	uint32_t	bit;
212 
213 	for (bit = hibit; len--; bit--) {
214 		val <<= 1;
215 		val |= ((resp[bit / 32]) >> (bit % 32)) & 1;
216 	}
217 	return (val);
218 }
219 
220 void
221 sda_mem_getstring(uint32_t *resp, char *s, int hibit, int len)
222 {
223 	while (len--) {
224 		*s++ = sda_mem_getbits(resp, hibit, 8);
225 		hibit -= 8;
226 	}
227 	*s = 0;
228 }
229 
230 uint32_t
231 sda_mem_maxclk(sda_slot_t *slot)
232 {
233 	static const uint32_t	mult[16] = {
234 		0, 10, 12, 13, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 70, 80
235 	};
236 
237 	static const uint32_t	units[8] = {
238 		10000, 100000, 1000000, 10000000, 0, 0, 0, 0,
239 	};
240 	uint8_t			ts;
241 
242 	ts = sda_mem_getbits(slot->s_rcsd, 103, 8);
243 
244 	return ((units[ts & 0x7]) * (mult[(ts >> 3) & 0xf]));
245 }
246 
247 int
248 sda_mem_parse_cid_csd(sda_slot_t *slot)
249 {
250 	uint32_t	*rcid;
251 	uint32_t	*rcsd;
252 	int		csdver;
253 	uint16_t	rblen;
254 	uint16_t	bshift;
255 	uint32_t	cmult;
256 	uint32_t	csize;
257 
258 	rcid = slot->s_rcid;
259 	rcsd = slot->s_rcsd;
260 
261 	csdver = sda_mem_getbits(rcsd, 127, 2);
262 
263 	if (slot->s_flags & SLOTF_SDMEM) {
264 		switch (csdver) {
265 		case 0:
266 			csize = sda_mem_getbits(rcsd, 73, 12);
267 			rblen = (1 << sda_mem_getbits(rcsd, 83, 4));
268 			cmult = (4 << sda_mem_getbits(rcsd, 49, 3));
269 			bshift = 9;
270 			break;
271 		case 1:
272 			rblen = 512;
273 			csize = sda_mem_getbits(rcsd, 69, 22);
274 			cmult = 1024;
275 			bshift = 0;
276 			break;
277 		default:
278 			sda_slot_err(slot, "Unknown SD CSD version (%d)",
279 			    csdver);
280 			return (DDI_FAILURE);
281 		}
282 
283 		slot->s_mfg = sda_mem_getbits(rcid, 127, 8);
284 		sda_mem_getstring(rcid, slot->s_oem, 119, 2);
285 		sda_mem_getstring(rcid, slot->s_prod, 103, 5);
286 		slot->s_majver = sda_mem_getbits(rcid, 63, 4);
287 		slot->s_minver = sda_mem_getbits(rcid, 59, 4);
288 		slot->s_serial =  sda_mem_getbits(rcid, 55, 32);
289 		slot->s_year = sda_mem_getbits(rcid, 19, 8) + 2000;
290 		slot->s_month = sda_mem_getbits(rcid, 11, 4);
291 
292 	} else if (slot->s_flags & SLOTF_MMC) {
293 		if ((csdver < 1) || (csdver > 2)) {
294 			sda_slot_err(slot, "Unknown MMC CSD version (%d)",
295 			    csdver);
296 			return (DDI_FAILURE);
297 		}
298 
299 		switch (sda_mem_getbits(rcsd, 125, 4)) {
300 		case 0:	/* MMC 1.0 - 1.2 */
301 		case 1:	/* MMC 1.4 */
302 			slot->s_mfg = sda_mem_getbits(rcid, 127, 24);
303 			slot->s_oem[0] = 0;
304 			sda_mem_getstring(rcid, slot->s_prod, 103, 7);
305 			slot->s_majver = sda_mem_getbits(rcid, 47, 4);
306 			slot->s_minver = sda_mem_getbits(rcid, 43, 4);
307 			slot->s_serial =  sda_mem_getbits(rcid, 39, 24);
308 			break;
309 
310 		case 2:	/* MMC 2.0 - 2.2 */
311 		case 3:	/* MMC 3.1 - 3.3 */
312 		case 4:	/* MMC 4.x */
313 			slot->s_mfg = sda_mem_getbits(rcid, 127, 8);
314 			sda_mem_getstring(rcid, slot->s_oem, 119, 2);
315 			sda_mem_getstring(rcid, slot->s_prod, 103, 6);
316 			slot->s_majver = sda_mem_getbits(rcid, 55, 4);
317 			slot->s_minver = sda_mem_getbits(rcid, 51, 4);
318 			slot->s_serial =  sda_mem_getbits(rcid, 47, 32);
319 			break;
320 
321 		default:
322 			/* this error isn't fatal to us */
323 			sda_slot_err(slot, "Unknown MMCA version (%d)",
324 			    sda_mem_getbits(rcsd, 125, 4));
325 			break;
326 		}
327 
328 		slot->s_year = sda_mem_getbits(rcid, 11, 4) + 1997;
329 		slot->s_month = sda_mem_getbits(rcid, 15, 4);
330 
331 		csize = sda_mem_getbits(rcsd, 73, 12);
332 		rblen = (1 << sda_mem_getbits(rcsd, 83, 4));
333 		cmult = (4 << sda_mem_getbits(rcsd, 49, 3));
334 		bshift = 9;
335 
336 	} else {
337 
338 		sda_slot_err(slot, "Card type unknown");
339 		return (DDI_FAILURE);
340 	}
341 
342 	/*
343 	 * These fields are common to all known MMC/SDcard memory cards.
344 	 *
345 	 * The spec requires that block size 512 be supported.
346 	 * The media may have a different native size, but 512
347 	 * byte blocks will always work.  This is true for SDcard,
348 	 * and apparently for MMC as well.
349 	 */
350 	rblen = max(rblen, 512);	/* paranoia */
351 	slot->s_nblks = (csize + 1) * cmult * (rblen / 512);
352 	slot->s_bshift = bshift;
353 	slot->s_blksz = 512;
354 
355 	slot->s_r2w = (1 << sda_mem_getbits(rcsd, 28, 3));
356 	slot->s_ccc = sda_mem_getbits(rcsd, 95, 12);
357 	slot->s_perm_wp = sda_mem_getbits(rcsd, 13, 1);
358 	slot->s_temp_wp = sda_mem_getbits(rcsd, 12, 1);
359 	slot->s_dsr = sda_mem_getbits(rcsd, 76, 1);
360 
361 	if (((slot->s_ccc & (1 << 4)) == 0) ||
362 	    (slot->s_perm_wp != 0) || (slot->s_temp_wp != 0)) {
363 		slot->s_flags &= ~SLOTF_WRITABLE;
364 	}
365 
366 	return (DDI_SUCCESS);
367 }
368