1/* $NetBSD: sd.c,v 1.13 2024/05/09 15:11:11 tsutsui Exp $ */ 2 3/* 4 * Copyright (c) 1988 University of Utah. 5 * Copyright (c) 1990, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * Van Jacobson of Lawrence Berkeley Laboratory and the Systems 10 * Programming Group of the University of Utah Computer Science Department. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * from: Utah $Hdr: sd.c 1.9 92/12/21$ 37 * 38 * @(#)sd.c 8.1 (Berkeley) 6/10/93 39 */ 40 41/* 42 * SCSI CCS disk driver 43 */ 44 45#include <sys/param.h> 46#include <sys/disklabel.h> 47 48#include <lib/libsa/stand.h> 49 50#include <hp300/stand/common/samachdep.h> 51#include <hp300/stand/common/conf.h> 52 53#define _IOCTL_ 54#include <hp300/stand/common/scsireg.h> 55#include <hp300/stand/common/scsivar.h> 56 57struct sdminilabel { 58 u_short npart; 59 u_long offset[MAXPARTITIONS]; 60}; 61 62struct sd_softc { 63 int sc_ctlr; 64 int sc_unit; 65 int sc_part; 66 char sc_retry; 67 char sc_alive; 68 short sc_blkshift; 69 struct sdminilabel sc_pinfo; 70#ifdef SUPPORT_CD 71 uint8_t sc_type; 72#endif 73}; 74 75#define SDRETRY 2 76 77static int sdinit(int ,int); 78static int sdgetinfo(struct sd_softc *); 79 80struct disklabel sdlabel; 81struct sd_softc sd_softc[NSCSI][NSD]; 82 83static int 84sdinit(int ctlr, int unit) 85{ 86 struct sd_softc *ss = &sd_softc[ctlr][unit]; 87 u_char stat; 88#ifdef SUPPORT_CD 89 struct scsi_inquiry inqbuf; 90#endif 91 int capbuf[2]; 92 93 stat = scsi_test_unit_rdy(ctlr, unit); 94 if (stat) { 95 /* drive may be doing RTZ - wait a bit */ 96 if (stat == STS_CHECKCOND) { 97 DELAY(1000000); 98 stat = scsi_test_unit_rdy(ctlr, unit); 99 } 100 if (stat) { 101 printf("sd(%d,%d,0,0): init failed (stat=%x)\n", 102 ctlr, unit, stat); 103 return 0; 104 } 105 } 106#ifdef SUPPORT_CD 107 /* 108 * try to get the disk type. 109 */ 110 memset(&inqbuf, 0, sizeof(inqbuf)); 111 stat = scsi_inquiry(ctlr, unit, (u_char *)&inqbuf, sizeof(inqbuf)); 112 if (stat == 0) { 113 /* to fake a disklabel on CD-ROM */ 114 ss->sc_type = inqbuf.type & SID_TYPE; 115 } else { 116 /* assume a disk by default */ 117 ss->sc_type = T_DIRECT; 118 } 119#endif 120 /* 121 * try to get the drive block size. 122 */ 123 capbuf[0] = 0; 124 capbuf[1] = 0; 125 stat = scsi_read_capacity(ctlr, unit, 126 (u_char *)capbuf, sizeof(capbuf)); 127 if (stat == 0) { 128 if (capbuf[1] > DEV_BSIZE) 129 for (; capbuf[1] > DEV_BSIZE; capbuf[1] >>= 1) 130 ++ss->sc_blkshift; 131 } 132 ss->sc_alive = 1; 133 return 1; 134} 135 136char io_buf[MAXBSIZE]; 137 138static int 139sdgetinfo(struct sd_softc *ss) 140{ 141 struct sdminilabel *pi = &ss->sc_pinfo; 142 struct disklabel *lp = &sdlabel; 143 char *msg; 144 int err, savepart; 145 size_t i; 146 147 memset((void *)lp, 0, sizeof *lp); 148 lp->d_secsize = (DEV_BSIZE << ss->sc_blkshift); 149 150 /* Disklabel is always from RAW_PART. */ 151 savepart = ss->sc_part; 152 ss->sc_part = RAW_PART; 153 err = sdstrategy(ss, F_READ, LABELSECTOR, 154 lp->d_secsize ? lp->d_secsize : DEV_BSIZE, io_buf, &i); 155 ss->sc_part = savepart; 156 157 if (err) { 158 printf("sdgetinfo: sdstrategy error %d\n", err); 159 return 0; 160 } 161 162 msg = getdisklabel(io_buf, lp); 163 if (msg) { 164#ifdef SUPPORT_CD 165 if (ss->sc_type == T_CDROM) { 166 /* assume a whole disk region is ISO9660 */ 167 pi->npart = 3; 168 pi->offset[0] = 0; 169 pi->offset[1] = -1; 170 pi->offset[2] = 0; 171 } else 172#endif 173 { 174 printf("sd(%d,%d,%d): WARNING: %s\n", 175 ss->sc_ctlr, ss->sc_unit, ss->sc_part, msg); 176 pi->npart = 3; 177 pi->offset[0] = pi->offset[1] = -1; 178 pi->offset[2] = 0; 179 } 180 } else { 181 pi->npart = lp->d_npartitions; 182 for (i = 0; i < pi->npart; i++) 183 pi->offset[i] = lp->d_partitions[i].p_size == 0 ? 184 -1 : lp->d_partitions[i].p_offset; 185 } 186 return 1; 187} 188 189int 190sdopen(struct open_file *f, ...) 191{ 192 va_list ap; 193 int ctlr, unit, part; 194 struct sd_softc *ss; 195 196 va_start(ap, f); 197 ctlr = va_arg(ap, int); 198 unit = va_arg(ap, int); 199 part = va_arg(ap, int); 200 va_end(ap); 201 202#ifdef SD_DEBUG 203 if (debug) 204 printf("sdopen: ctlr=%d unit=%d part=%d\n", 205 ctlr, unit, part); 206#endif 207 208 if (ctlr >= NSCSI || scsialive(ctlr) == 0) 209 return EADAPT; 210 if (unit >= NSD) 211 return ECTLR; 212 ss = &sd_softc[ctlr][unit]; 213 ss->sc_part = part; 214 ss->sc_unit = unit; 215 ss->sc_ctlr = ctlr; 216 if (ss->sc_alive == 0) { 217 if (sdinit(ctlr, unit) == 0) 218 return ENXIO; 219 if (sdgetinfo(ss) == 0) 220 return ERDLAB; 221 } 222 if (part != RAW_PART && /* always allow RAW_PART to be opened */ 223 (part >= ss->sc_pinfo.npart || ss->sc_pinfo.offset[part] == -1)) 224 return EPART; 225 f->f_devdata = (void *)ss; 226 return 0; 227} 228 229int 230sdclose(struct open_file *f) 231{ 232 struct sd_softc *ss = f->f_devdata; 233 234 /* 235 * Mark the disk `not alive' so that the disklabel 236 * will be re-loaded at next open. 237 */ 238 memset(ss, 0, sizeof(sd_softc)); 239 f->f_devdata = NULL; 240 241 return 0; 242} 243 244int 245sdstrategy(void *devdata, int func, daddr_t dblk, size_t size, void *v_buf, 246 size_t *rsize) 247{ 248 struct sd_softc *ss = devdata; 249 uint8_t *buf = v_buf; 250 int ctlr = ss->sc_ctlr; 251 int unit = ss->sc_unit; 252 u_int nblk = size >> ss->sc_blkshift; 253 daddr_t blk; 254 int stat; 255 256 if (size == 0) 257 return 0; 258 259 /* 260 * Don't do partition translation on the `raw partition'. 261 */ 262 blk = (dblk + ((ss->sc_part == RAW_PART) ? 0 : 263 ss->sc_pinfo.offset[ss->sc_part])) >> ss->sc_blkshift; 264 265 ss->sc_retry = 0; 266 267#ifdef SD_DEBUG 268 if (debug) 269 printf("sdstrategy(%d,%d): size=%d blk=%d nblk=%d\n", 270 ctlr, unit, size, blk, nblk); 271#endif 272 273retry: 274 if (func == F_READ) 275 stat = scsi_tt_read(ctlr, unit, buf, size, blk, nblk); 276 else 277 stat = scsi_tt_write(ctlr, unit, buf, size, blk, nblk); 278 if (stat) { 279 printf("sd(%d,%d,%d): block=%x, error=0x%x\n", 280 ctlr, unit, ss->sc_part, blk, stat); 281 if (++ss->sc_retry > SDRETRY) 282 return EIO; 283 goto retry; 284 } 285 *rsize = size; 286 287 return 0; 288} 289