xref: /netbsd-src/sys/arch/next68k/stand/boot/sd.c (revision 783bf7199cac9069640f0160391cee3cc6f37264)
1 /*      $NetBSD: sd.c,v 1.17 2023/02/12 08:25:09 tsutsui Exp $        */
2 /*
3  * Copyright (c) 1994 Rolf Grossmann
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
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
19  *
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.
30  */
31 
32 #include <sys/param.h>
33 #include <sys/disklabel.h>
34 #include <sys/bootblock.h>
35 #include <dev/scsipi/scsi_spc.h>
36 #include <dev/scsipi/scsipi_all.h>
37 #include <dev/scsipi/scsi_all.h>
38 #include <dev/scsipi/scsipi_disk.h>
39 #include <lib/libsa/stand.h>
40 #include <lib/libkern/libkern.h> /* for bzero() */
41 
42 #include "dmareg.h"
43 #include "scsivar.h"
44 #include "samachdep.h"
45 
46 #ifdef SD_DEBUG
47 #define DPRINTF(x) printf x;
48 #else
49 #define DPRINTF(x)
50 #endif
51 
52 struct sdminilabel {
53     u_short npart;
54     long offset[MAXPARTITIONS+1]; /* offset from absolute block 0! */
55 };
56 
57 struct  sd_softc {
58     int sc_unit;
59     int sc_lun;
60     int sc_part;
61     int sc_dev_bsize;
62     struct sdminilabel sc_pinfo;
63 };
64 
65 #define NSD 7
66 #define MAXRETRIES 5	/* must be at least one */
67 
68 int sdprobe(char target, char lun);
69 int sdgetinfo(struct sd_softc *ss);
70 
71 int
sdprobe(char target,char lun)72 sdprobe(char target, char lun)
73 {
74     struct scsi_test_unit_ready cdb1;
75     struct scsipi_inquiry cdb2;
76     struct scsipi_inquiry_data inq;
77     int error, retries;
78     int count;
79 
80     memset(&cdb1, 0, sizeof(cdb1));
81     cdb1.opcode =  SCSI_TEST_UNIT_READY;
82 
83     retries = 0;
84     do {
85 	    count = 0;
86 	error = scsiicmd(target, lun, (u_char *)&cdb1, sizeof(cdb1), NULL, &count);
87 	if (error == -SCSI_BUSY) {
88 		register int N = 10000000; while (--N > 0);
89 	}
90     } while ((error == -SCSI_CHECK || error == -SCSI_BUSY)
91 	     && retries++ < MAXRETRIES);
92 
93     if (error)
94 	return error<0 ? ENODEV : error;
95 
96     memset(&cdb2, 0, sizeof(cdb2));
97     cdb2.opcode = INQUIRY;
98     cdb2.length = SCSIPI_INQUIRY_LENGTH_SCSI2;
99     count = SCSIPI_INQUIRY_LENGTH_SCSI2;
100     error = scsiicmd(target, lun, (u_char *)&cdb2, sizeof(cdb2),
101 		     (char *)&inq, &count);
102     if (error != 0)
103       return error<0 ? EHER : error;
104 
105     if ((inq.device & SID_TYPE) != T_DIRECT
106 	&& (inq.device & SID_TYPE) != T_CDROM)
107       return EUNIT;	/* not a disk */
108 
109     DPRINTF(("booting disk %s.\n", inq.vendor));
110 
111     return 0;
112 }
113 
114 int
sdgetinfo(struct sd_softc * ss)115 sdgetinfo(struct sd_softc *ss)
116 {
117     struct scsipi_read_capacity_10 cdb;
118     struct scsipi_read_capacity_10_data cap;
119     struct sdminilabel *pi = &ss->sc_pinfo;
120     struct next68k_disklabel *label;
121     int error, i, blklen;
122     char io_buf[NEXT68K_LABEL_SIZE+NEXT68K_LABEL_OFFSET];
123     int count;
124     int sc_blkshift = 0;
125 
126     memset(&cdb, 0, sizeof(cdb));
127     cdb.opcode = READ_CAPACITY_10;
128     count = sizeof(cap);
129     error = scsiicmd(ss->sc_unit, ss->sc_lun, (u_char *)&cdb, sizeof(cdb),
130 		     (char *)&cap, &count);
131     if (error != 0)
132 	return error<0 ? EHER : error;
133     blklen = (cap.length[0]<<24) + (cap.length[1]<<16)
134 	     + (cap.length[2]<<8) + cap.length[3];
135 
136     /* avoid division by zero trap even on possible xfer errors */
137     if (blklen == 0)
138 	blklen = DEV_BSIZE;
139     ss->sc_dev_bsize = blklen;
140 
141     ss->sc_pinfo.offset[ss->sc_part] = 0; /* read absolute sector */
142     error = sdstrategy(ss, F_READ, NEXT68K_LABEL_SECTOR,
143 		       NEXT68K_LABEL_SIZE+NEXT68K_LABEL_OFFSET, io_buf, (unsigned int *)&i);
144     if (error != 0) {
145 	DPRINTF(("sdgetinfo: sdstrategy error %d\n", error));
146         return(ERDLAB);
147     }
148     label = (struct next68k_disklabel *)(io_buf+NEXT68K_LABEL_OFFSET);
149 
150     if (!IS_DISKLABEL(label)) /*  || (label->cd_flags & CD_UNINIT)!=0) */
151 	return EUNLAB;		/* bad magic */
152 
153     /* XXX calculate checksum ... for now we rely on the magic number */
154     DPRINTF(("Disk is %s (%s, %s).\n",
155 	     label->cd_label,label->cd_name, label->cd_type));
156 
157     while (label->cd_secsize > blklen)
158     {
159 	blklen <<= 1;
160 	++sc_blkshift;
161     }
162     if (label->cd_secsize < blklen)
163     {
164 	printf("bad label sectorsize (%d) or device blocksize (%d).\n",
165 	       label->cd_secsize, blklen>>sc_blkshift);
166 	return ENXIO;
167     }
168     pi->npart = 0;
169     for(i=0; i<MAXPARTITIONS; i++) {
170 	if (label->cd_partitions[i].cp_size > 0) {
171 	    pi->offset[pi->npart] = (label->cd_partitions[i].cp_offset
172 				     + label->cd_front) << sc_blkshift;
173 	}
174 	else
175 	    pi->offset[pi->npart] = -1;
176 	DPRINTF (("%d: [%d]=%ld\n", i, pi->npart, pi->offset[pi->npart]));
177 	pi->npart++;
178 	if (pi->npart == RAW_PART)
179 	    pi->npart++;
180     }
181     pi->offset[RAW_PART] = -1;
182 
183     return 0;
184 }
185 
186 int
sdopen(struct open_file * f,...)187 sdopen(struct open_file *f, ...)
188 {
189     va_list ap;
190     int count, lun, part;
191     register struct sd_softc *ss;
192     char unit, cnt;
193     int error;
194 
195     va_start(ap, f);
196     count = va_arg(ap, int);
197     lun = va_arg(ap, int);
198     part = va_arg(ap, int);
199     va_end(ap);
200 
201     DPRINTF(("open: sd(%d,%d,%d)\n", count, lun, part));
202 
203     if (lun >= NSD)
204 	return EUNIT;
205 
206     scsi_init();
207 
208     for(cnt=0, unit=0; unit < NSD; unit++)
209     {
210 	DPRINTF(("trying target %d lun %d.\n", unit, lun));
211 	error = sdprobe(unit, lun);
212 	if (error == 0)
213 	{
214 	    if (cnt++ == count)
215 		break;
216 	}
217 	else if (error != EUNIT)
218 	    return error;
219     }
220 
221     if (unit >= NSD)
222 	return EUNIT;
223 
224     ss = alloc(sizeof(struct sd_softc));
225     ss->sc_unit = unit;
226     ss->sc_lun = lun;
227     ss->sc_part = part;
228 
229     if ((error = sdgetinfo(ss)) != 0)
230 	return error;
231 
232     if ((unsigned char)part >= ss->sc_pinfo.npart
233 	|| ss->sc_pinfo.offset[(int)part] == -1)
234 	return EPART;
235 
236     f->f_devdata = ss;
237     return 0;
238 }
239 
240 int
sdclose(struct open_file * f)241 sdclose(struct open_file *f)
242 {
243     register struct sd_softc *ss = f->f_devdata;
244 
245     dealloc(ss, sizeof(struct sd_softc));
246     return 0;
247 }
248 
249 int
sdstrategy(void * devdata,int rw,daddr_t dblk,size_t size,void * buf,size_t * rsize)250 sdstrategy(void *devdata, int rw, daddr_t dblk, size_t size,
251 	   void *buf, size_t *rsize)
252 {
253     struct sd_softc *ss = devdata;
254     u_long blk = dblk + ss->sc_pinfo.offset[ss->sc_part];
255     struct scsipi_rw_10 cdb;
256     int error;
257 
258     if (size == 0)
259 	return 0;
260 
261     if (rw != F_READ)
262     {
263 	printf("sdstrategy: write not implemented.\n");
264 	return EOPNOTSUPP;
265     }
266 
267     *rsize = 0;
268     while (size > 0) {
269 	    u_long nblks;
270 	    int tsize;
271 	    if (size > MAX_DMASIZE)
272 		    tsize = MAX_DMASIZE;
273 	    else
274 		    tsize = size;
275 
276 	    nblks = howmany(tsize, ss->sc_dev_bsize);
277 
278 	    DPRINTF(("sdstrategy: read block %ld, %d bytes (%ld blks a %d bytes).\n",
279 		     blk, tsize, nblks, ss->sc_dev_bsize));
280 
281 	    memset(&cdb, 0, sizeof(cdb));
282 	    cdb.opcode = READ_10;
283 	    cdb.addr[0] = (blk & 0xff000000) >> 24;
284 	    cdb.addr[1] = (blk & 0xff0000) >> 16;
285 	    cdb.addr[2] = (blk & 0xff00) >> 8;
286 	    cdb.addr[3] = blk & 0xff;
287 	    cdb.length[0] = (nblks & 0xff00) >> 8;
288 	    cdb.length[1] = nblks & 0xff;
289 
290 	    error = scsiicmd(ss->sc_unit, ss->sc_lun,
291 			     (u_char *)&cdb, sizeof(cdb), (char *)buf + *rsize, &tsize);
292 	    if (error != 0)
293 	    {
294 		    DPRINTF(("sdstrategy: scsiicmd failed: %d = %s.\n", error, strerror(error)));
295 		    return error<0 ? EIO : error;
296 	    }
297 	    *rsize += tsize;
298 	    size -= tsize;
299 	    blk += nblks;
300     }
301     DPRINTF(("sdstrategy: read %d bytes\n", *rsize));
302     return 0;
303 }
304