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