1 /* $NetBSD: sd.c,v 1.10 2006/08/04 02:09:19 mhitch Exp $ */
3 * Copyright (c) 1994 Rolf Grossmann
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by Rolf Grossmann.
17 * 4. The name of the author may not be used to endorse or promote products
18 * derived from this software without specific prior written permission
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/param.h>
33 #include <sys/disklabel.h>
34 #include <dev/scsipi/scsi_spc.h>
35 #include <dev/scsipi/scsipi_all.h>
36 #include <dev/scsipi/scsi_all.h>
37 #include <dev/scsipi/scsipi_disk.h>
38 #include <lib/libsa/stand.h>
39 #include <lib/libkern/libkern.h> /* for bzero() */
43 #define DPRINTF(x) printf x;
50 long offset
[MAXPARTITIONS
+1]; /* offset from absolute block 0! */
58 struct sdminilabel sc_pinfo
;
62 #define MAXRETRIES 5 /* must be at least one */
65 int scsiicmd(char, char, u_char
*, int, char *, int *);
66 int sdstrategy(struct sd_softc
*ss
, int rw
, daddr_t dblk
, size_t size
,
67 void *buf
, size_t *rsize
);
68 int sdprobe(char target
, char lun
);
69 int sdgetinfo(struct sd_softc
*ss
);
70 int sdopen(struct open_file
*f
, char count
, char lun
, char part
);
71 int sdclose(struct open_file
*f
);
74 sdprobe(char target
, char lun
)
76 struct scsi_test_unit_ready cdb1
;
77 struct scsipi_inquiry cdb2
;
78 struct scsipi_inquiry_data inq
;
82 memset(&cdb1
, 0, sizeof(cdb1
));
83 cdb1
.opcode
= SCSI_TEST_UNIT_READY
;
88 error
= scsiicmd(target
, lun
, (u_char
*)&cdb1
, sizeof(cdb1
), NULL
, &count
);
89 if (error
== -SCSI_BUSY
) {
90 register int N
= 10000000; while (--N
> 0);
92 } while ((error
== -SCSI_CHECK
|| error
== -SCSI_BUSY
)
93 && retries
++ < MAXRETRIES
);
96 return error
<0 ? ENODEV
: error
;
98 memset(&cdb2
, 0, sizeof(cdb2
));
99 cdb2
.opcode
= INQUIRY
;
100 cdb2
.length
= sizeof(inq
);
101 count
= sizeof (inq
);
102 error
= scsiicmd(target
, lun
, (u_char
*)&cdb2
, sizeof(cdb2
),
103 (char *)&inq
, &count
);
105 return error
<0 ? EHER
: error
;
107 if ((inq
.device
& SID_TYPE
) != T_DIRECT
108 && (inq
.device
& SID_TYPE
) != T_CDROM
)
109 return EUNIT
; /* not a disk */
111 DPRINTF(("booting disk %s.\n", inq
.vendor
));
117 sdgetinfo(struct sd_softc
*ss
)
119 struct scsipi_read_capacity_10 cdb
;
120 struct scsipi_read_capacity_10_data cap
;
121 struct sdminilabel
*pi
= &ss
->sc_pinfo
;
122 struct next68k_disklabel
*label
;
123 int error
, i
, blklen
;
124 char io_buf
[NEXT68K_LABEL_SIZE
+NEXT68K_LABEL_OFFSET
];
128 memset(&cdb
, 0, sizeof(cdb
));
129 cdb
.opcode
= READ_CAPACITY_10
;
131 error
= scsiicmd(ss
->sc_unit
, ss
->sc_lun
, (u_char
*)&cdb
, sizeof(cdb
),
132 (char *)&cap
, &count
);
134 return error
<0 ? EHER
: error
;
135 blklen
= (cap
.length
[0]<<24) + (cap
.length
[1]<<16)
136 + (cap
.length
[2]<<8) + cap
.length
[3];
137 ss
->sc_dev_bsize
= blklen
;
139 ss
->sc_pinfo
.offset
[ss
->sc_part
] = 0; /* read absolute sector */
140 error
= sdstrategy(ss
, F_READ
, NEXT68K_LABEL_SECTOR
,
141 NEXT68K_LABEL_SIZE
+NEXT68K_LABEL_OFFSET
, io_buf
, (unsigned int *)&i
);
143 DPRINTF(("sdgetinfo: sdstrategy error %d\n", error
));
146 label
= (struct next68k_disklabel
*)(io_buf
+NEXT68K_LABEL_OFFSET
);
148 if (!IS_DISKLABEL(label
)) /* || (label->cd_flags & CD_UNINIT)!=0) */
149 return EUNLAB
; /* bad magic */
151 /* XXX calculate checksum ... for now we rely on the magic number */
152 DPRINTF(("Disk is %s (%s, %s).\n",
153 label
->cd_label
,label
->cd_name
, label
->cd_type
));
155 while (label
->cd_secsize
> blklen
)
160 if (label
->cd_secsize
< blklen
)
162 printf("bad label sectorsize (%d) or device blocksize (%d).\n",
163 label
->cd_secsize
, blklen
>>sc_blkshift
);
167 for(i
=0; i
<MAXPARTITIONS
; i
++) {
168 if (label
->cd_partitions
[i
].cp_size
> 0) {
169 pi
->offset
[pi
->npart
] = (label
->cd_partitions
[i
].cp_offset
170 + label
->cd_front
) << sc_blkshift
;
173 pi
->offset
[pi
->npart
] = -1;
174 DPRINTF (("%d: [%d]=%ld\n", i
, pi
->npart
, pi
->offset
[pi
->npart
]));
176 if (pi
->npart
== RAW_PART
)
179 pi
->offset
[RAW_PART
] = -1;
185 sdopen(struct open_file
*f
, char count
, char lun
, char part
)
187 register struct sd_softc
*ss
;
191 DPRINTF(("open: sd(%d,%d,%d)\n", count
, lun
, part
));
198 for(cnt
=0, unit
=0; unit
< NSD
; unit
++)
200 DPRINTF(("trying target %d lun %d.\n", unit
, lun
));
201 error
= sdprobe(unit
, lun
);
207 else if (error
!= EUNIT
)
214 ss
= alloc(sizeof(struct sd_softc
));
219 if ((error
= sdgetinfo(ss
)) != 0)
222 if ((unsigned char)part
>= ss
->sc_pinfo
.npart
223 || ss
->sc_pinfo
.offset
[(int)part
] == -1)
231 sdclose(struct open_file
*f
)
233 register struct sd_softc
*ss
= f
->f_devdata
;
235 dealloc(ss
, sizeof(struct sd_softc
));
240 sdstrategy(struct sd_softc
*ss
, int rw
, daddr_t dblk
, size_t size
,
241 void *buf
, size_t *rsize
)
243 u_long blk
= dblk
+ ss
->sc_pinfo
.offset
[ss
->sc_part
];
244 struct scsipi_rw_10 cdb
;
252 printf("sdstrategy: write not implemented.\n");
260 if (size
> MAX_DMASIZE
)
265 nblks
= howmany(tsize
, ss
->sc_dev_bsize
);
267 DPRINTF(("sdstrategy: read block %ld, %d bytes (%ld blks a %d bytes).\n",
268 blk
, tsize
, nblks
, ss
->sc_dev_bsize
));
270 memset(&cdb
, 0, sizeof(cdb
));
271 cdb
.opcode
= READ_10
;
272 cdb
.addr
[0] = (blk
& 0xff000000) >> 24;
273 cdb
.addr
[1] = (blk
& 0xff0000) >> 16;
274 cdb
.addr
[2] = (blk
& 0xff00) >> 8;
275 cdb
.addr
[3] = blk
& 0xff;
276 cdb
.length
[0] = (nblks
& 0xff00) >> 8;
277 cdb
.length
[1] = nblks
& 0xff;
279 error
= scsiicmd(ss
->sc_unit
, ss
->sc_lun
,
280 (u_char
*)&cdb
, sizeof(cdb
), (char *)buf
+ *rsize
, &tsize
);
283 DPRINTF(("sdstrategy: scsiicmd failed: %d = %s.\n", error
, strerror(error
)));
284 return error
<0 ? EIO
: error
;
290 DPRINTF(("sdstrategy: read %d bytes\n", *rsize
));