1 /* $NetBSD: mmemcard.c,v 1.17 2008/06/11 14:55:30 tsutsui Exp $ */
4 * Copyright (c) 2002 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: mmemcard.c,v 1.17 2008/06/11 14:55:30 tsutsui Exp $");
35 #include <sys/param.h>
38 #include <sys/device.h>
39 #include <sys/disklabel.h>
41 #include <sys/kernel.h>
42 #include <sys/malloc.h>
45 #include <sys/systm.h>
46 #include <sys/vnode.h>
49 #include <dreamcast/dev/maple/maple.h>
50 #include <dreamcast/dev/maple/mapleconf.h>
52 #define MMEM_MAXACCSIZE 1012 /* (255*4) - 8 = 253*32 / 8 */
54 struct mmem_funcdef
{ /* XXX assuming little-endian structure packing */
56 ra
: 4, /* number of access / read */
57 wa
: 4, /* number of access / write */
58 bb
: 8, /* block size / 32 - 1 */
59 pt
: 8; /* number of partition - 1 */
62 struct mmem_request_read_data
{
69 struct mmem_response_read_data
{
70 uint32_t func_code
; /* function code (big endian) */
71 uint32_t blkno
; /* 512byte block number (big endian) */
72 uint8_t data
[MMEM_MAXACCSIZE
];
75 struct mmem_request_write_data
{
78 uint8_t phase
; /* 0, 1, 2, 3: for each 128 byte */
80 uint8_t data
[MMEM_MAXACCSIZE
];
82 #define MMEM_SIZE_REQW(sc) ((sc)->sc_waccsz + 8)
84 struct mmem_request_get_media_info
{
86 uint32_t pt
; /* pt (1 byte) and unused 3 bytes */
89 struct mmem_media_info
{
90 uint16_t maxblk
, minblk
;
92 uint16_t fatpos
, fatsz
;
93 uint16_t dirpos
, dirsz
;
99 struct mmem_response_media_info
{
100 uint32_t func_code
; /* function code (big endian) */
101 struct mmem_media_info info
;
105 struct device sc_dev
;
107 struct device
*sc_parent
;
108 struct maple_unit
*sc_unit
;
109 struct maple_devinfo
*sc_devinfo
;
112 MMEM_INIT
, /* during initialization */
113 MMEM_INIT2
, /* during initialization */
114 MMEM_IDLE
, /* init done, not in I/O */
115 MMEM_READ
, /* in read operation */
116 MMEM_WRITE1
, /* in write operation (read and compare) */
117 MMEM_WRITE2
, /* in write operation (write) */
118 MMEM_DETACH
/* detaching */
121 int sc_npt
; /* number of partitions */
122 int sc_bsize
; /* block size */
123 int sc_wacc
; /* number of write access per block */
124 int sc_waccsz
; /* size of a write access */
125 int sc_racc
; /* number of read access per block */
126 int sc_raccsz
; /* size of a read access */
130 #define MMEM_PT_OK 1 /* partition is alive */
131 struct disk pt_dk
; /* disk(9) */
132 struct mmem_media_info pt_info
; /* geometry per part */
134 char pt_name
[16 /* see device.h */ + 4 /* ".255" */];
137 /* write request buffer (only one is used at a time) */
139 struct mmem_request_read_data req_read
;
140 struct mmem_request_write_data req_write
;
141 struct mmem_request_get_media_info req_minfo
;
143 #define sc_reqr sc_req.req_read
144 #define sc_reqw sc_req.req_write
145 #define sc_reqm sc_req.req_minfo
147 /* pending buffers */
148 struct bufq_state
*sc_q
;
150 /* current I/O access */
155 #define MMEM_MAXRETRY 12
159 * minor number layout (mmemdetach() depends on this layout):
161 * 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
162 * |---------------------| |---------------------| |---------|
163 * unit part disklabel partition
165 #define MMEM_PART(diskunit) ((diskunit) & 0xff)
166 #define MMEM_UNIT(diskunit) ((diskunit) >> 8)
167 #define MMEM_DISKMINOR(unit, part, disklabel_partition) \
168 DISKMINOR(((unit) << 8) | (part), (disklabel_partition))
170 static int mmemmatch(struct device
*, struct cfdata
*, void *);
171 static void mmemattach(struct device
*, struct device
*, void *);
172 static void mmem_defaultlabel(struct mmem_softc
*, struct mmem_pt
*,
174 static int mmemdetach(struct device
*, int);
175 static void mmem_intr(void *, struct maple_response
*, int, int);
176 static void mmem_printerror(const char *, int, int, uint32_t);
177 static void mmemstart(struct mmem_softc
*);
178 static void mmemstart_bp(struct mmem_softc
*);
179 static void mmemstart_write2(struct mmem_softc
*);
180 static void mmemdone(struct mmem_softc
*, struct mmem_pt
*, int);
182 dev_type_open(mmemopen
);
183 dev_type_close(mmemclose
);
184 dev_type_read(mmemread
);
185 dev_type_write(mmemwrite
);
186 dev_type_ioctl(mmemioctl
);
187 dev_type_strategy(mmemstrategy
);
189 const struct bdevsw mmem_bdevsw
= {
190 mmemopen
, mmemclose
, mmemstrategy
, mmemioctl
, nodump
,
194 const struct cdevsw mmem_cdevsw
= {
195 mmemopen
, mmemclose
, mmemread
, mmemwrite
, mmemioctl
,
196 nostop
, notty
, nopoll
, nommap
, nokqfilter
, D_DISK
199 CFATTACH_DECL(mmem
, sizeof(struct mmem_softc
),
200 mmemmatch
, mmemattach
, mmemdetach
, NULL
);
202 extern struct cfdriver mmem_cd
;
204 struct dkdriver mmemdkdriver
= { mmemstrategy
};
207 mmemmatch(struct device
*parent
, struct cfdata
*cf
, void *aux
)
209 struct maple_attach_args
*ma
= aux
;
211 return ma
->ma_function
== MAPLE_FN_MEMCARD
? MAPLE_MATCH_FUNC
: 0;
215 mmemattach(struct device
*parent
, struct device
*self
, void *aux
)
217 struct mmem_softc
*sc
= (void *)self
;
218 struct maple_attach_args
*ma
= aux
;
222 struct mmem_funcdef s
;
225 sc
->sc_parent
= parent
;
226 sc
->sc_unit
= ma
->ma_unit
;
227 sc
->sc_devinfo
= ma
->ma_devinfo
;
229 funcdef
.v
= maple_get_function_data(ma
->ma_devinfo
, MAPLE_FN_MEMCARD
);
230 printf(": Memory card\n");
231 printf("%s: %d part, %d bytes/block, ",
233 sc
->sc_npt
= funcdef
.s
.pt
+ 1,
234 sc
->sc_bsize
= (funcdef
.s
.bb
+ 1) << 5);
235 if ((sc
->sc_wacc
= funcdef
.s
.wa
) == 0)
236 printf("no write, ");
238 printf("%d acc/write, ", sc
->sc_wacc
);
239 if ((sc
->sc_racc
= funcdef
.s
.ra
) == 0)
242 printf("%d acc/read\n", sc
->sc_racc
);
245 * start init sequence
247 sc
->sc_stat
= MMEM_INIT
;
248 bufq_alloc(&sc
->sc_q
, "disksort", BUFQ_SORT_RAWBLOCK
);
250 /* check consistency */
251 if (sc
->sc_wacc
!= 0) {
252 sc
->sc_waccsz
= sc
->sc_bsize
/ sc
->sc_wacc
;
253 if (sc
->sc_bsize
!= sc
->sc_waccsz
* sc
->sc_wacc
) {
254 printf("%s: write access isn't equally divided\n",
255 sc
->sc_dev
.dv_xname
);
256 sc
->sc_wacc
= 0; /* no write */
257 } else if (sc
->sc_waccsz
> MMEM_MAXACCSIZE
) {
258 printf("%s: write access size is too large\n",
259 sc
->sc_dev
.dv_xname
);
260 sc
->sc_wacc
= 0; /* no write */
263 if (sc
->sc_racc
!= 0) {
264 sc
->sc_raccsz
= sc
->sc_bsize
/ sc
->sc_racc
;
265 if (sc
->sc_bsize
!= sc
->sc_raccsz
* sc
->sc_racc
) {
266 printf("%s: read access isn't equally divided\n",
267 sc
->sc_dev
.dv_xname
);
268 sc
->sc_racc
= 0; /* no read */
269 } else if (sc
->sc_raccsz
> MMEM_MAXACCSIZE
) {
270 printf("%s: read access size is too large\n",
271 sc
->sc_dev
.dv_xname
);
272 sc
->sc_racc
= 0; /* no read */
275 if (sc
->sc_wacc
== 0 && sc
->sc_racc
== 0) {
276 printf("%s: device doesn't support read nor write\n",
277 sc
->sc_dev
.dv_xname
);
281 /* per-part structure */
282 sc
->sc_pt
= malloc(sizeof(struct mmem_pt
) * sc
->sc_npt
, M_DEVBUF
,
285 for (i
= 0; i
< sc
->sc_npt
; i
++) {
286 sprintf(sc
->sc_pt
[i
].pt_name
, "%s.%d", sc
->sc_dev
.dv_xname
, i
);
289 maple_set_callback(parent
, sc
->sc_unit
, MAPLE_FN_MEMCARD
,
293 * get capacity (start from partition 0)
295 sc
->sc_reqm
.func_code
= htobe32(MAPLE_FUNC(MAPLE_FN_MEMCARD
));
297 maple_command(sc
->sc_parent
, sc
->sc_unit
, MAPLE_FN_MEMCARD
,
298 MAPLE_COMMAND_GETMINFO
, sizeof sc
->sc_reqm
/ 4, &sc
->sc_reqm
, 0);
302 mmemdetach(struct device
*self
, int flags
)
304 struct mmem_softc
*sc
= (struct mmem_softc
*) self
;
307 int minor_l
, minor_h
;
309 sc
->sc_stat
= MMEM_DETACH
; /* just in case */
314 if ((bp
= sc
->sc_bp
) != NULL
) {
316 bp
->b_resid
= bp
->b_bcount
;
319 while ((bp
= bufq_get(sc
->sc_q
)) != NULL
) {
321 bp
->b_resid
= bp
->b_bcount
;
329 #ifdef __HAVE_OLD_DISKLABEL
330 #error This code assumes DISKUNIT() is contiguous in minor number.
332 minor_l
= MMEM_DISKMINOR(device_unit(self
), 0, 0);
333 minor_h
= MMEM_DISKMINOR(device_unit(self
), sc
->sc_npt
- 1,
335 vdevgone(bdevsw_lookup_major(&mmem_bdevsw
), minor_l
, minor_h
, VBLK
);
336 vdevgone(cdevsw_lookup_major(&mmem_cdevsw
), minor_l
, minor_h
, VCHR
);
339 * free per-partition structure
345 for (i
= 0; i
< sc
->sc_npt
; i
++) {
346 if (sc
->sc_pt
[i
].pt_flags
& MMEM_PT_OK
) {
347 disk_detach(&sc
->sc_pt
[i
].pt_dk
);
348 disk_destroy(&sc
->sc_pt
[i
].pt_dk
);
351 free(sc
->sc_pt
, M_DEVBUF
);
359 mmem_defaultlabel(struct mmem_softc
*sc
, struct mmem_pt
*pt
,
363 memset(d
, 0, sizeof *d
);
366 d
->d_type
= DTYPE_FLOPPY
; /* XXX? */
368 strncpy(d
->d_typename
, sc
->sc_devinfo
->di_product_name
,
369 sizeof d
->d_typename
);
370 strcpy(d
->d_packname
, "fictitious");
371 d
->d_secsize
= sc
->sc_bsize
;
372 d
->d_ntracks
= 1; /* XXX */
373 d
->d_nsectors
= d
->d_secpercyl
= 8; /* XXX */
374 d
->d_secperunit
= pt
->pt_info
.maxblk
- pt
->pt_info
.minblk
+ 1;
375 d
->d_ncylinders
= d
->d_secperunit
/ d
->d_secpercyl
;
376 d
->d_rpm
= 1; /* when 4 acc/write */
378 d
->d_npartitions
= RAW_PART
+ 1;
379 d
->d_partitions
[RAW_PART
].p_size
= d
->d_secperunit
;
381 d
->d_magic
= d
->d_magic2
= DISKMAGIC
;
382 d
->d_checksum
= dkcksum(d
);
386 * called back from maple bus driver
389 mmem_intr(void *dev
, struct maple_response
*response
, int sz
, int flags
)
391 struct mmem_softc
*sc
= dev
;
392 struct mmem_response_read_data
*r
= (void *) response
->data
;
393 struct mmem_response_media_info
*rm
= (void *) response
->data
;
400 switch (sc
->sc_stat
) {
402 /* checking part geometry */
403 part
= sc
->sc_reqm
.pt
;
404 pt
= &sc
->sc_pt
[part
];
405 switch ((maple_response_t
) response
->response_code
) {
406 case MAPLE_RESPONSE_DATATRF
:
407 pt
->pt_info
= rm
->info
;
408 format_bytes(pbuf
, sizeof(pbuf
),
410 ((pt
->pt_info
.maxblk
- pt
->pt_info
.minblk
+ 1)
412 printf("%s: %s, blk %d %d, inf %d, fat %d %d, dir %d %d, icon %d, data %d\n",
415 pt
->pt_info
.maxblk
, pt
->pt_info
.minblk
,
417 pt
->pt_info
.fatpos
, pt
->pt_info
.fatsz
,
418 pt
->pt_info
.dirpos
, pt
->pt_info
.dirsz
,
422 disk_init(&pt
->pt_dk
, pt
->pt_name
, &mmemdkdriver
);
423 disk_attach(&pt
->pt_dk
);
425 mmem_defaultlabel(sc
, pt
, pt
->pt_dk
.dk_label
);
427 /* this partition is active */
428 pt
->pt_flags
= MMEM_PT_OK
;
432 printf("%s: init: unexpected response %#x, sz %d\n",
433 pt
->pt_name
, be32toh(response
->response_code
), sz
);
436 if (++part
== sc
->sc_npt
) {
439 * XXX Read a block and discard the contents (only to
440 * turn off the access indicator on Visual Memory).
443 sc
->sc_reqr
.func_code
=
444 htobe32(MAPLE_FUNC(MAPLE_FN_MEMCARD
));
446 sc
->sc_reqr
.block
= htobe16(pt
->pt_info
.minblk
);
447 sc
->sc_reqr
.phase
= 0;
448 maple_command(sc
->sc_parent
, sc
->sc_unit
,
449 MAPLE_FN_MEMCARD
, MAPLE_COMMAND_BREAD
,
450 sizeof sc
->sc_reqr
/ 4, &sc
->sc_reqr
, 0);
451 sc
->sc_stat
= MMEM_INIT2
;
453 sc
->sc_stat
= MMEM_IDLE
; /* init done */
456 sc
->sc_reqm
.pt
= part
;
457 maple_command(sc
->sc_parent
, sc
->sc_unit
,
458 MAPLE_FN_MEMCARD
, MAPLE_COMMAND_GETMINFO
,
459 sizeof sc
->sc_reqm
/ 4, &sc
->sc_reqm
, 0);
464 /* XXX just discard */
465 sc
->sc_stat
= MMEM_IDLE
; /* init done */
471 switch ((maple_response_t
) response
->response_code
) {
472 case MAPLE_RESPONSE_DATATRF
: /* read done */
473 off
= sc
->sc_raccsz
* sc
->sc_reqr
.phase
;
474 memcpy(sc
->sc_iobuf
+ off
, r
->data
+ off
,
477 if (++sc
->sc_reqr
.phase
== sc
->sc_racc
) {
479 pt
= &sc
->sc_pt
[sc
->sc_reqr
.pt
];
483 maple_command(sc
->sc_parent
, sc
->sc_unit
,
484 MAPLE_FN_MEMCARD
, MAPLE_COMMAND_BREAD
,
485 sizeof sc
->sc_reqr
/ 4, &sc
->sc_reqr
, 0);
488 case MAPLE_RESPONSE_FILEERR
:
489 mmem_printerror(sc
->sc_pt
[sc
->sc_reqr
.pt
].pt_name
,
491 r
->func_code
/* XXX */);
492 mmemstart_bp(sc
); /* retry */
495 printf("%s: read: unexpected response %#x %#x, sz %d\n",
496 sc
->sc_pt
[sc
->sc_reqr
.pt
].pt_name
,
497 be32toh(response
->response_code
),
498 be32toh(r
->func_code
), sz
);
499 mmemstart_bp(sc
); /* retry */
504 case MMEM_WRITE1
: /* read before write / verify after write */
507 switch ((maple_response_t
) response
->response_code
) {
508 case MAPLE_RESPONSE_DATATRF
: /* read done */
509 off
= sc
->sc_raccsz
* sc
->sc_reqr
.phase
;
510 if (memcmp(r
->data
+ off
, sc
->sc_iobuf
+ off
,
513 * data differ, start writing
515 mmemstart_write2(sc
);
516 } else if (++sc
->sc_reqr
.phase
== sc
->sc_racc
) {
518 * all phase done and compared equal
520 pt
= &sc
->sc_pt
[sc
->sc_reqr
.pt
];
524 maple_command(sc
->sc_parent
, sc
->sc_unit
,
525 MAPLE_FN_MEMCARD
, MAPLE_COMMAND_BREAD
,
526 sizeof sc
->sc_reqr
/ 4, &sc
->sc_reqr
, 0);
529 case MAPLE_RESPONSE_FILEERR
:
530 mmem_printerror(sc
->sc_pt
[sc
->sc_reqr
.pt
].pt_name
,
532 r
->func_code
/* XXX */);
533 mmemstart_write2(sc
); /* start writing */
536 printf("%s: verify: unexpected response %#x %#x, sz %d\n",
537 sc
->sc_pt
[sc
->sc_reqr
.pt
].pt_name
,
538 be32toh(response
->response_code
),
539 be32toh(r
->func_code
), sz
);
540 mmemstart_write2(sc
); /* start writing */
545 case MMEM_WRITE2
: /* write */
548 switch ((maple_response_t
) response
->response_code
) {
549 case MAPLE_RESPONSE_OK
: /* write done */
550 if (sc
->sc_reqw
.phase
== sc
->sc_wacc
) {
552 mmemstart_bp(sc
); /* start verify */
553 } else if (++sc
->sc_reqw
.phase
== sc
->sc_wacc
) {
555 maple_command(sc
->sc_parent
, sc
->sc_unit
,
556 MAPLE_FN_MEMCARD
, MAPLE_COMMAND_GETLASTERR
,
557 2 /* no data */ , &sc
->sc_reqw
,
558 MAPLE_FLAG_CMD_PERIODIC_TIMING
);
561 memcpy(sc
->sc_reqw
.data
, sc
->sc_iobuf
+
562 sc
->sc_waccsz
* sc
->sc_reqw
.phase
,
564 maple_command(sc
->sc_parent
, sc
->sc_unit
,
565 MAPLE_FN_MEMCARD
, MAPLE_COMMAND_BWRITE
,
566 MMEM_SIZE_REQW(sc
) / 4, &sc
->sc_reqw
,
567 MAPLE_FLAG_CMD_PERIODIC_TIMING
);
570 case MAPLE_RESPONSE_FILEERR
:
571 mmem_printerror(sc
->sc_pt
[sc
->sc_reqw
.pt
].pt_name
,
573 r
->func_code
/* XXX */);
574 mmemstart_write2(sc
); /* retry writing */
577 printf("%s: write: unexpected response %#x, %#x, sz %d\n",
578 sc
->sc_pt
[sc
->sc_reqw
.pt
].pt_name
,
579 be32toh(response
->response_code
),
580 be32toh(r
->func_code
), sz
);
581 mmemstart_write2(sc
); /* retry writing */
592 mmem_printerror(const char *head
, int rd
, int blk
, uint32_t code
)
595 printf("%s: error %sing blk %d:", head
, rd
? "read" : "writ", blk
);
600 printf(" Phase error");
602 printf(" Block error");
604 printf(" Write error");
606 printf(" Length error");
608 printf(" CRC error");
610 printf(" Unknown error %#x", code
& ~077);
615 mmemopen(dev_t dev
, int flags
, int devtype
, struct lwp
*l
)
617 int diskunit
, unit
, part
, labelpart
;
618 struct mmem_softc
*sc
;
621 diskunit
= DISKUNIT(dev
);
622 unit
= MMEM_UNIT(diskunit
);
623 part
= MMEM_PART(diskunit
);
624 labelpart
= DISKPART(dev
);
625 if ((sc
= device_lookup_private(&mmem_cd
, unit
)) == NULL
626 || sc
->sc_stat
== MMEM_INIT
627 || sc
->sc_stat
== MMEM_INIT2
628 || part
>= sc
->sc_npt
|| (pt
= &sc
->sc_pt
[part
])->pt_flags
== 0)
633 pt
->pt_dk
.dk_copenmask
|= (1 << labelpart
);
636 pt
->pt_dk
.dk_bopenmask
|= (1 << labelpart
);
644 mmemclose(dev_t dev
, int flags
, int devtype
, struct lwp
*l
)
646 int diskunit
, unit
, part
, labelpart
;
647 struct mmem_softc
*sc
;
650 diskunit
= DISKUNIT(dev
);
651 unit
= MMEM_UNIT(diskunit
);
652 part
= MMEM_PART(diskunit
);
653 sc
= device_lookup_private(&mmem_cd
, unit
);
654 pt
= &sc
->sc_pt
[part
];
655 labelpart
= DISKPART(dev
);
659 pt
->pt_dk
.dk_copenmask
&= ~(1 << labelpart
);
662 pt
->pt_dk
.dk_bopenmask
&= ~(1 << labelpart
);
670 mmemstrategy(struct buf
*bp
)
672 int diskunit
, unit
, part
, labelpart
;
673 struct mmem_softc
*sc
;
675 daddr_t off
, nblk
, cnt
;
677 diskunit
= DISKUNIT(bp
->b_dev
);
678 unit
= MMEM_UNIT(diskunit
);
679 part
= MMEM_PART(diskunit
);
680 if ((sc
= device_lookup_private(&mmem_cd
, unit
)) == NULL
681 || sc
->sc_stat
== MMEM_INIT
682 || sc
->sc_stat
== MMEM_INIT2
683 || part
>= sc
->sc_npt
|| (pt
= &sc
->sc_pt
[part
])->pt_flags
== 0)
687 printf("%s: mmemstrategy: blkno %d, count %ld\n",
688 pt
->pt_name
, bp
->b_blkno
, bp
->b_bcount
);
691 if (bp
->b_flags
& B_READ
) {
692 if (sc
->sc_racc
== 0)
693 goto inval
; /* no read */
694 } else if (sc
->sc_wacc
== 0) {
695 bp
->b_error
= EROFS
; /* no write */
699 if (bp
->b_blkno
& ~(~(daddr_t
)0 >> (DEV_BSHIFT
+ 1 /* sign bit */))
700 || (bp
->b_bcount
% sc
->sc_bsize
) != 0)
703 cnt
= howmany(bp
->b_bcount
, sc
->sc_bsize
);
705 goto done
; /* no work */
707 off
= bp
->b_blkno
* DEV_BSIZE
/ sc
->sc_bsize
;
709 /* offset to disklabel partition */
710 labelpart
= DISKPART(bp
->b_dev
);
711 if (labelpart
== RAW_PART
) {
712 nblk
= pt
->pt_info
.maxblk
- pt
->pt_info
.minblk
+ 1;
715 nblk
= pt
->pt_dk
.dk_label
->d_partitions
[labelpart
].p_offset
;
716 nblk
+= pt
->pt_dk
.dk_label
->d_partitions
[labelpart
].p_size
;
719 /* deal with the EOF condition */
720 if (off
+ cnt
> nblk
) {
727 bp
->b_resid
= bp
->b_bcount
- (cnt
* sc
->sc_bsize
);
730 bp
->b_rawblkno
= off
;
732 /* queue this transfer */
733 bufq_put(sc
->sc_q
, bp
);
735 if (sc
->sc_stat
== MMEM_IDLE
)
740 inval
: bp
->b_error
= EINVAL
;
741 done
: bp
->b_resid
= bp
->b_bcount
;
746 * start I/O operations
749 mmemstart(struct mmem_softc
*sc
)
755 if ((bp
= bufq_get(sc
->sc_q
)) == NULL
) {
756 sc
->sc_stat
= MMEM_IDLE
;
757 maple_enable_unit_ping(sc
->sc_parent
, sc
->sc_unit
,
758 MAPLE_FN_MEMCARD
, 1);
763 sc
->sc_cnt
= howmany(bp
->b_bcount
- bp
->b_resid
, sc
->sc_bsize
);
765 sc
->sc_iobuf
= bp
->b_data
;
768 pt
= &sc
->sc_pt
[MMEM_PART(DISKUNIT(bp
->b_dev
))];
770 disk_busy(&pt
->pt_dk
);
774 * I/O access will fail if the removal detection (by maple driver)
775 * occurs before finishing the I/O, so disable it.
776 * We are sending commands, and the removal detection is still alive.
778 maple_enable_unit_ping(sc
->sc_parent
, sc
->sc_unit
, MAPLE_FN_MEMCARD
, 0);
784 * start/retry a specified I/O operation
787 mmemstart_bp(struct mmem_softc
*sc
)
794 diskunit
= DISKUNIT(bp
->b_dev
);
795 part
= MMEM_PART(diskunit
);
796 pt
= &sc
->sc_pt
[part
];
799 if (sc
->sc_retry
++ > MMEM_MAXRETRY
) {
800 /* retry count exceeded */
801 mmemdone(sc
, pt
, EIO
);
806 * Start the first phase (phase# = 0).
809 sc
->sc_stat
= (bp
->b_flags
& B_READ
) ? MMEM_READ
: MMEM_WRITE1
;
810 sc
->sc_reqr
.func_code
= htobe32(MAPLE_FUNC(MAPLE_FN_MEMCARD
));
811 sc
->sc_reqr
.pt
= part
;
812 sc
->sc_reqr
.block
= htobe16(bp
->b_rawblkno
);
813 sc
->sc_reqr
.phase
= 0; /* first phase */
814 maple_command(sc
->sc_parent
, sc
->sc_unit
, MAPLE_FN_MEMCARD
,
815 MAPLE_COMMAND_BREAD
, sizeof sc
->sc_reqr
/ 4, &sc
->sc_reqr
, 0);
819 mmemstart_write2(struct mmem_softc
*sc
)
826 diskunit
= DISKUNIT(bp
->b_dev
);
827 part
= MMEM_PART(diskunit
);
828 pt
= &sc
->sc_pt
[part
];
831 if (sc
->sc_retry
++ > MMEM_MAXRETRY
- 2 /* spare for verify read */) {
832 /* retry count exceeded */
833 mmemdone(sc
, pt
, EIO
);
838 * Start the first phase (phase# = 0).
841 sc
->sc_stat
= MMEM_WRITE2
;
842 sc
->sc_reqw
.func_code
= htobe32(MAPLE_FUNC(MAPLE_FN_MEMCARD
));
843 sc
->sc_reqw
.pt
= part
;
844 sc
->sc_reqw
.block
= htobe16(bp
->b_rawblkno
);
845 sc
->sc_reqw
.phase
= 0; /* first phase */
846 memcpy(sc
->sc_reqw
.data
, sc
->sc_iobuf
/* + sc->sc_waccsz * phase */,
848 maple_command(sc
->sc_parent
, sc
->sc_unit
, MAPLE_FN_MEMCARD
,
849 MAPLE_COMMAND_BWRITE
, MMEM_SIZE_REQW(sc
) / 4, &sc
->sc_reqw
,
850 MAPLE_FLAG_CMD_PERIODIC_TIMING
);
854 mmemdone(struct mmem_softc
*sc
, struct mmem_pt
*pt
, int err
)
856 struct buf
*bp
= sc
->sc_bp
;
863 bcnt
= (char *)sc
->sc_iobuf
- (char *)bp
->b_data
;
864 bp
->b_resid
= bp
->b_bcount
- bcnt
;
866 /* raise error if no block is read */
873 sc
->sc_iobuf
+= sc
->sc_bsize
;
874 if (--sc
->sc_cnt
== 0) {
876 /* terminate current transfer */
879 disk_unbusy(&pt
->pt_dk
,
880 (char *)sc
->sc_iobuf
- (char *)bp
->b_data
,
881 sc
->sc_stat
== MMEM_READ
);
885 /* go next transfer */
896 mmemread(dev_t dev
, struct uio
*uio
, int flags
)
899 return physio(mmemstrategy
, NULL
, dev
, B_READ
, minphys
, uio
);
903 mmemwrite(dev_t dev
, struct uio
*uio
, int flags
)
906 return physio(mmemstrategy
, NULL
, dev
, B_WRITE
, minphys
, uio
);
910 mmemioctl(dev_t dev
, u_long cmd
, void *data
, int flag
, struct lwp
*l
)
912 int diskunit
, unit
, part
;
913 struct mmem_softc
*sc
;
916 diskunit
= DISKUNIT(dev
);
917 unit
= MMEM_UNIT(diskunit
);
918 part
= MMEM_PART(diskunit
);
919 sc
= device_lookup_private(&mmem_cd
, unit
);
920 pt
= &sc
->sc_pt
[part
];
924 *(struct disklabel
*)data
= *pt
->pt_dk
.dk_label
; /* XXX */
928 /* generic maple ioctl */
929 return maple_unit_ioctl(sc
->sc_parent
, sc
->sc_unit
, cmd
, data
,