1 1.20 rin /* $NetBSD: sc.c,v 1.20 2024/09/25 09:08:22 rin Exp $ */ 2 1.1 tsutsui 3 1.1 tsutsui /* 4 1.1 tsutsui * Copyright (c) 1992 OMRON Corporation. 5 1.1 tsutsui * 6 1.1 tsutsui * This code is derived from software contributed to Berkeley by 7 1.1 tsutsui * OMRON Corporation. 8 1.1 tsutsui * 9 1.1 tsutsui * Redistribution and use in source and binary forms, with or without 10 1.1 tsutsui * modification, are permitted provided that the following conditions 11 1.1 tsutsui * are met: 12 1.1 tsutsui * 1. Redistributions of source code must retain the above copyright 13 1.1 tsutsui * notice, this list of conditions and the following disclaimer. 14 1.1 tsutsui * 2. Redistributions in binary form must reproduce the above copyright 15 1.1 tsutsui * notice, this list of conditions and the following disclaimer in the 16 1.1 tsutsui * documentation and/or other materials provided with the distribution. 17 1.1 tsutsui * 3. All advertising materials mentioning features or use of this software 18 1.1 tsutsui * must display the following acknowledgement: 19 1.1 tsutsui * This product includes software developed by the University of 20 1.1 tsutsui * California, Berkeley and its contributors. 21 1.1 tsutsui * 4. Neither the name of the University nor the names of its contributors 22 1.1 tsutsui * may be used to endorse or promote products derived from this software 23 1.1 tsutsui * without specific prior written permission. 24 1.1 tsutsui * 25 1.1 tsutsui * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 1.1 tsutsui * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 1.1 tsutsui * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 1.1 tsutsui * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 1.1 tsutsui * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 1.1 tsutsui * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 1.1 tsutsui * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 1.1 tsutsui * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 1.1 tsutsui * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 1.1 tsutsui * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 1.1 tsutsui * SUCH DAMAGE. 36 1.1 tsutsui * 37 1.1 tsutsui * @(#)sc.c 8.1 (Berkeley) 6/10/93 38 1.1 tsutsui */ 39 1.1 tsutsui /* 40 1.1 tsutsui * Copyright (c) 1992, 1993 41 1.1 tsutsui * The Regents of the University of California. All rights reserved. 42 1.1 tsutsui * 43 1.1 tsutsui * This code is derived from software contributed to Berkeley by 44 1.1 tsutsui * OMRON Corporation. 45 1.1 tsutsui * 46 1.1 tsutsui * Redistribution and use in source and binary forms, with or without 47 1.1 tsutsui * modification, are permitted provided that the following conditions 48 1.1 tsutsui * are met: 49 1.1 tsutsui * 1. Redistributions of source code must retain the above copyright 50 1.1 tsutsui * notice, this list of conditions and the following disclaimer. 51 1.1 tsutsui * 2. Redistributions in binary form must reproduce the above copyright 52 1.1 tsutsui * notice, this list of conditions and the following disclaimer in the 53 1.1 tsutsui * documentation and/or other materials provided with the distribution. 54 1.1 tsutsui * 3. Neither the name of the University nor the names of its contributors 55 1.1 tsutsui * may be used to endorse or promote products derived from this software 56 1.1 tsutsui * without specific prior written permission. 57 1.1 tsutsui * 58 1.1 tsutsui * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 59 1.1 tsutsui * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 60 1.1 tsutsui * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 61 1.1 tsutsui * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 62 1.1 tsutsui * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 63 1.1 tsutsui * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 64 1.1 tsutsui * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 65 1.1 tsutsui * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 66 1.1 tsutsui * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 67 1.1 tsutsui * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 68 1.1 tsutsui * SUCH DAMAGE. 69 1.1 tsutsui * 70 1.1 tsutsui * @(#)sc.c 8.1 (Berkeley) 6/10/93 71 1.1 tsutsui */ 72 1.1 tsutsui 73 1.1 tsutsui /* 74 1.1 tsutsui * sc.c -- SCSI Protocole Controller (SPC) driver 75 1.1 tsutsui * remaked by A.Fujita, MAR-11-199 76 1.1 tsutsui */ 77 1.1 tsutsui 78 1.1 tsutsui 79 1.3 tsutsui #define NSC 2 80 1.1 tsutsui 81 1.1 tsutsui #include <sys/param.h> 82 1.1 tsutsui #include <luna68k/stand/boot/samachdep.h> 83 1.1 tsutsui #include <luna68k/stand/boot/scsireg.h> 84 1.1 tsutsui #include <luna68k/stand/boot/scsivar.h> 85 1.1 tsutsui 86 1.1 tsutsui #define SCSI_ID 7 87 1.1 tsutsui 88 1.9 tsutsui static void screset(struct scsi_softc *); 89 1.9 tsutsui static void scprobe(struct scsi_softc *, uint, uint); 90 1.12 tsutsui static int issue_select(struct scsidevice *, uint8_t); 91 1.12 tsutsui static void ixfer_start(struct scsidevice *, int, uint8_t, int); 92 1.12 tsutsui static void ixfer_out(struct scsidevice *, int, uint8_t *); 93 1.12 tsutsui static void ixfer_in(struct scsidevice *, int, uint8_t *); 94 1.12 tsutsui static int scrun(int, int, uint8_t *, int, uint8_t *, int, volatile int *); 95 1.1 tsutsui static int scfinish(int); 96 1.9 tsutsui static void scabort(struct scsi_softc *); 97 1.1 tsutsui 98 1.1 tsutsui struct scsi_softc scsi_softc[NSC]; 99 1.1 tsutsui 100 1.1 tsutsui /* 101 1.1 tsutsui * Initialize SPC & Data Structure 102 1.1 tsutsui */ 103 1.1 tsutsui 104 1.1 tsutsui int 105 1.9 tsutsui scinit(int ctlr, void *addr) 106 1.1 tsutsui { 107 1.3 tsutsui struct scsi_softc *hs; 108 1.9 tsutsui uint id; 109 1.3 tsutsui 110 1.9 tsutsui if (ctlr < 0 || ctlr >= NSC) 111 1.3 tsutsui return 0; 112 1.3 tsutsui 113 1.9 tsutsui hs = &scsi_softc[ctlr]; 114 1.9 tsutsui hs->sc_ctlr = ctlr; 115 1.9 tsutsui hs->sc_spc = addr; 116 1.1 tsutsui 117 1.1 tsutsui hs->sc_flags = 0; 118 1.1 tsutsui hs->sc_phase = BUS_FREE_PHASE; 119 1.1 tsutsui hs->sc_target = SCSI_ID; 120 1.1 tsutsui 121 1.1 tsutsui hs->sc_cdb = NULL; 122 1.1 tsutsui hs->sc_cdblen = 0; 123 1.1 tsutsui hs->sc_buf = NULL; 124 1.1 tsutsui hs->sc_len = 0; 125 1.1 tsutsui hs->sc_lock = NULL; 126 1.1 tsutsui 127 1.1 tsutsui hs->sc_stat = 0; 128 1.1 tsutsui hs->sc_msg[0] = 0; 129 1.1 tsutsui 130 1.9 tsutsui screset(hs); 131 1.9 tsutsui 132 1.9 tsutsui for (id = 0; id < 7; id++) 133 1.9 tsutsui scprobe(hs, id, 0); 134 1.9 tsutsui 135 1.10 tsutsui return 1; 136 1.1 tsutsui } 137 1.1 tsutsui 138 1.14 tsutsui static void 139 1.9 tsutsui screset(struct scsi_softc *hs) 140 1.1 tsutsui { 141 1.9 tsutsui struct scsidevice *hd = hs->sc_spc; 142 1.1 tsutsui 143 1.9 tsutsui printf("sc%d at 0x%08lx: ", hs->sc_ctlr, (u_long)hs->sc_spc); 144 1.1 tsutsui 145 1.1 tsutsui /* 146 1.1 tsutsui * Disable interrupts then reset the FUJI chip. 147 1.1 tsutsui */ 148 1.1 tsutsui 149 1.1 tsutsui hd->scsi_sctl = SCTL_DISABLE | SCTL_CTRLRST; 150 1.1 tsutsui hd->scsi_scmd = 0; 151 1.1 tsutsui hd->scsi_pctl = 0; 152 1.1 tsutsui hd->scsi_temp = 0; 153 1.1 tsutsui hd->scsi_tch = 0; 154 1.1 tsutsui hd->scsi_tcm = 0; 155 1.1 tsutsui hd->scsi_tcl = 0; 156 1.1 tsutsui hd->scsi_ints = 0; 157 1.1 tsutsui 158 1.1 tsutsui /* We can use Asynchronous Transfer only */ 159 1.1 tsutsui printf("async"); 160 1.1 tsutsui 161 1.1 tsutsui /* 162 1.1 tsutsui * Configure MB89352 with its SCSI address, all 163 1.1 tsutsui * interrupts enabled & appropriate parity. 164 1.1 tsutsui */ 165 1.1 tsutsui hd->scsi_bdid = SCSI_ID; 166 1.1 tsutsui hd->scsi_sctl = SCTL_DISABLE | SCTL_ABRT_ENAB| 167 1.1 tsutsui SCTL_PARITY_ENAB | SCTL_RESEL_ENAB | 168 1.1 tsutsui SCTL_INTR_ENAB; 169 1.1 tsutsui printf(", parity"); 170 1.1 tsutsui 171 1.1 tsutsui DELAY(400); 172 1.1 tsutsui hd->scsi_sctl &= ~SCTL_DISABLE; 173 1.1 tsutsui 174 1.9 tsutsui printf(", ID %d\n", SCSI_ID); 175 1.9 tsutsui } 176 1.9 tsutsui 177 1.20 rin /* 178 1.20 rin * XXX 179 1.20 rin * sensebuf and inqbuf may be uninitialized for some cases. 180 1.20 rin * Real fix should be to check return values everywhere in 181 1.20 rin * scsi_request_sense(), scsi_immed_command(), and functions 182 1.20 rin * called from them. 183 1.20 rin */ 184 1.20 rin #pragma GCC diagnostic push /* XXX { */ 185 1.20 rin #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" 186 1.20 rin 187 1.9 tsutsui bool 188 1.9 tsutsui scident(uint ctlr, uint target, uint lun, struct scsi_inquiry *inqout, 189 1.9 tsutsui uint32_t *capout) 190 1.9 tsutsui { 191 1.9 tsutsui struct scsi_inquiry inqbuf; 192 1.9 tsutsui struct scsi_generic_cdb inq = { 193 1.9 tsutsui 6, 194 1.9 tsutsui { CMD_INQUIRY, 0, 0, 0, sizeof(inqbuf), 0 } 195 1.9 tsutsui }; 196 1.9 tsutsui uint32_t capbuf[2]; 197 1.9 tsutsui struct scsi_generic_cdb cap = { 198 1.9 tsutsui 10, 199 1.9 tsutsui { CMD_READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0 } 200 1.9 tsutsui }; 201 1.9 tsutsui int i; 202 1.9 tsutsui int tries = 10; 203 1.9 tsutsui 204 1.9 tsutsui /* 205 1.9 tsutsui * See if unit exists and is a disk then read block size & nblocks. 206 1.9 tsutsui */ 207 1.9 tsutsui while ((i = scsi_test_unit_rdy(ctlr, target, lun)) != 0) { 208 1.9 tsutsui if (i < 0 || --tries < 0) 209 1.9 tsutsui return false; 210 1.9 tsutsui if (i == STS_CHECKCOND) { 211 1.12 tsutsui uint8_t sensebuf[8]; 212 1.9 tsutsui struct scsi_xsense *sp = (struct scsi_xsense *)sensebuf; 213 1.9 tsutsui 214 1.9 tsutsui scsi_request_sense(ctlr, target, lun, sensebuf, 8); 215 1.9 tsutsui if (sp->class == 7 && sp->key == 6) 216 1.9 tsutsui /* drive doing an RTZ -- give it a while */ 217 1.9 tsutsui DELAY(1000000); 218 1.9 tsutsui } 219 1.9 tsutsui DELAY(1000); 220 1.9 tsutsui } 221 1.12 tsutsui if (scsi_immed_command(ctlr, target, lun, &inq, (uint8_t *)&inqbuf, 222 1.9 tsutsui sizeof(inqbuf)) || 223 1.12 tsutsui scsi_immed_command(ctlr, target, lun, &cap, (uint8_t *)&capbuf, 224 1.9 tsutsui sizeof(capbuf))) 225 1.9 tsutsui /* doesn't exist or not a CCS device */ 226 1.9 tsutsui return false; 227 1.9 tsutsui 228 1.9 tsutsui switch (inqbuf.type) { 229 1.9 tsutsui case 0: /* disk */ 230 1.9 tsutsui case 4: /* WORM */ 231 1.9 tsutsui case 5: /* CD-ROM */ 232 1.9 tsutsui case 7: /* Magneto-optical */ 233 1.9 tsutsui break; 234 1.9 tsutsui default: /* not a disk */ 235 1.9 tsutsui return false; 236 1.9 tsutsui } 237 1.9 tsutsui 238 1.9 tsutsui if (inqout != NULL) 239 1.9 tsutsui *inqout = inqbuf; 240 1.9 tsutsui if (capout != NULL) { 241 1.9 tsutsui /* assume big endian */ 242 1.9 tsutsui capout[0] = capbuf[0]; 243 1.9 tsutsui capout[1] = capbuf[1]; 244 1.9 tsutsui } 245 1.9 tsutsui 246 1.9 tsutsui return true; 247 1.9 tsutsui } 248 1.9 tsutsui 249 1.20 rin #pragma GCC diagnostic pop /* XXX } */ 250 1.20 rin 251 1.9 tsutsui static void 252 1.9 tsutsui scprobe(struct scsi_softc *hs, uint target, uint lun) 253 1.9 tsutsui { 254 1.9 tsutsui struct scsi_inquiry inqbuf; 255 1.18 tsutsui uint32_t capbuf[2], blocks, blksize; 256 1.9 tsutsui char idstr[32]; 257 1.9 tsutsui int i; 258 1.9 tsutsui 259 1.9 tsutsui if (!scident(hs->sc_ctlr, target, lun, &inqbuf, capbuf)) 260 1.9 tsutsui return; 261 1.9 tsutsui 262 1.18 tsutsui /* CMD_READ_CAPACITY returns the last logical data block address. */ 263 1.18 tsutsui blocks = capbuf[0] + 1; 264 1.18 tsutsui blksize = capbuf[1]; 265 1.18 tsutsui 266 1.9 tsutsui memcpy(idstr, &inqbuf.vendor_id, 28); 267 1.9 tsutsui for (i = 27; i > 23; --i) 268 1.9 tsutsui if (idstr[i] != ' ') 269 1.9 tsutsui break; 270 1.9 tsutsui idstr[i + 1] = '\0'; 271 1.9 tsutsui for (i = 23; i > 7; --i) 272 1.9 tsutsui if (idstr[i] != ' ') 273 1.9 tsutsui break; 274 1.9 tsutsui idstr[i + 1] = '\0'; 275 1.9 tsutsui for (i = 7; i >= 0; --i) 276 1.9 tsutsui if (idstr[i] != ' ') 277 1.9 tsutsui break; 278 1.9 tsutsui idstr[i + 1] = '\0'; 279 1.9 tsutsui 280 1.9 tsutsui printf(" ID %d: %s %s rev %s", target, idstr, &idstr[8], &idstr[24]); 281 1.18 tsutsui printf(", %d bytes/sect x %d sectors\n", blksize, blocks); 282 1.1 tsutsui } 283 1.1 tsutsui 284 1.1 tsutsui 285 1.1 tsutsui /* 286 1.1 tsutsui * SPC Arbitration/Selection routine 287 1.1 tsutsui */ 288 1.1 tsutsui 289 1.14 tsutsui static int 290 1.12 tsutsui issue_select(struct scsidevice *hd, uint8_t target) 291 1.1 tsutsui { 292 1.10 tsutsui 293 1.1 tsutsui hd->scsi_pctl = 0; 294 1.1 tsutsui hd->scsi_temp = (1 << SCSI_ID) | (1 << target); 295 1.1 tsutsui 296 1.5 tsutsui /* select timeout is hardcoded to 250ms */ 297 1.5 tsutsui hd->scsi_tch = 2; 298 1.5 tsutsui hd->scsi_tcm = 113; 299 1.5 tsutsui hd->scsi_tcl = 3; 300 1.1 tsutsui 301 1.1 tsutsui hd->scsi_scmd = SCMD_SELECT; 302 1.1 tsutsui 303 1.10 tsutsui return 1; 304 1.1 tsutsui } 305 1.1 tsutsui 306 1.1 tsutsui 307 1.1 tsutsui /* 308 1.1 tsutsui * SPC Manual Transfer routines 309 1.1 tsutsui */ 310 1.1 tsutsui 311 1.1 tsutsui /* not yet */ 312 1.1 tsutsui 313 1.1 tsutsui 314 1.1 tsutsui /* 315 1.1 tsutsui * SPC Program Transfer routines 316 1.1 tsutsui */ 317 1.1 tsutsui 318 1.14 tsutsui static void 319 1.12 tsutsui ixfer_start(struct scsidevice *hd, int len, uint8_t phase, int wait) 320 1.1 tsutsui { 321 1.10 tsutsui 322 1.1 tsutsui hd->scsi_tch = ((len & 0xff0000) >> 16); 323 1.1 tsutsui hd->scsi_tcm = ((len & 0x00ff00) >> 8); 324 1.1 tsutsui hd->scsi_tcl = (len & 0x0000ff); 325 1.1 tsutsui hd->scsi_pctl = phase; 326 1.1 tsutsui hd->scsi_scmd = SCMD_XFR | SCMD_PROG_XFR; 327 1.1 tsutsui } 328 1.1 tsutsui 329 1.14 tsutsui static void 330 1.12 tsutsui ixfer_out(struct scsidevice *hd, int len, uint8_t *buf) 331 1.1 tsutsui { 332 1.10 tsutsui 333 1.10 tsutsui for (; len > 0; len--) { 334 1.1 tsutsui while (hd->scsi_ssts & SSTS_DREG_FULL) { 335 1.1 tsutsui DELAY(5); 336 1.1 tsutsui } 337 1.1 tsutsui hd->scsi_dreg = *buf++; 338 1.1 tsutsui } 339 1.1 tsutsui } 340 1.1 tsutsui 341 1.14 tsutsui static void 342 1.12 tsutsui ixfer_in(struct scsidevice *hd, int len, uint8_t *buf) 343 1.1 tsutsui { 344 1.10 tsutsui 345 1.1 tsutsui for (; len > 0; len--) { 346 1.1 tsutsui while (hd->scsi_ssts & SSTS_DREG_EMPTY) { 347 1.1 tsutsui DELAY(5); 348 1.1 tsutsui } 349 1.1 tsutsui *buf++ = hd->scsi_dreg; 350 1.1 tsutsui } 351 1.1 tsutsui } 352 1.1 tsutsui 353 1.1 tsutsui 354 1.1 tsutsui /* 355 1.1 tsutsui * SPC drive routines 356 1.1 tsutsui */ 357 1.1 tsutsui 358 1.14 tsutsui static int 359 1.12 tsutsui scrun(int ctlr, int target, uint8_t *cdb, int cdblen, uint8_t *buf, int len, 360 1.1 tsutsui volatile int *lock) 361 1.1 tsutsui { 362 1.6 tsutsui struct scsi_softc *hs; 363 1.6 tsutsui struct scsidevice *hd; 364 1.6 tsutsui 365 1.6 tsutsui if (ctlr < 0 || ctlr >= NSC) 366 1.6 tsutsui return 0; 367 1.6 tsutsui 368 1.6 tsutsui hs = &scsi_softc[ctlr]; 369 1.9 tsutsui hd = hs->sc_spc; 370 1.9 tsutsui if (hd == NULL) 371 1.9 tsutsui return 0; 372 1.1 tsutsui 373 1.13 tsutsui if ((hd->scsi_ssts & (SSTS_INITIATOR | SSTS_TARGET | SSTS_BUSY)) != 0) 374 1.10 tsutsui return 0; 375 1.1 tsutsui 376 1.1 tsutsui hs->sc_flags = 0; 377 1.1 tsutsui hs->sc_phase = ARB_SEL_PHASE; 378 1.9 tsutsui hs->sc_target = target; 379 1.1 tsutsui 380 1.1 tsutsui hs->sc_cdb = cdb; 381 1.1 tsutsui hs->sc_cdblen = cdblen; 382 1.1 tsutsui hs->sc_buf = buf; 383 1.1 tsutsui hs->sc_len = len; 384 1.1 tsutsui hs->sc_lock = lock; 385 1.1 tsutsui 386 1.1 tsutsui hs->sc_stat = 0; 387 1.1 tsutsui hs->sc_msg[0] = 0; 388 1.1 tsutsui 389 1.1 tsutsui *(hs->sc_lock) = SC_IN_PROGRESS; 390 1.1 tsutsui issue_select(hd, hs->sc_target); 391 1.1 tsutsui 392 1.10 tsutsui return 1; 393 1.1 tsutsui } 394 1.1 tsutsui 395 1.14 tsutsui static int 396 1.1 tsutsui scfinish(int ctlr) 397 1.1 tsutsui { 398 1.1 tsutsui struct scsi_softc *hs = &scsi_softc[ctlr]; 399 1.1 tsutsui int status = hs->sc_stat; 400 1.1 tsutsui 401 1.1 tsutsui hs->sc_flags = 0; 402 1.1 tsutsui hs->sc_phase = BUS_FREE_PHASE; 403 1.1 tsutsui hs->sc_target = SCSI_ID; 404 1.1 tsutsui 405 1.1 tsutsui hs->sc_cdb = NULL; 406 1.1 tsutsui hs->sc_cdblen = 0; 407 1.1 tsutsui hs->sc_buf = NULL; 408 1.1 tsutsui hs->sc_len = 0; 409 1.1 tsutsui hs->sc_lock = NULL; 410 1.1 tsutsui 411 1.1 tsutsui hs->sc_stat = 0; 412 1.1 tsutsui hs->sc_msg[0] = 0; 413 1.1 tsutsui 414 1.10 tsutsui return status; 415 1.1 tsutsui } 416 1.1 tsutsui 417 1.14 tsutsui static void 418 1.9 tsutsui scabort(struct scsi_softc *hs) 419 1.1 tsutsui { 420 1.9 tsutsui struct scsidevice *hd = hs->sc_spc; 421 1.1 tsutsui int len; 422 1.1 tsutsui 423 1.1 tsutsui printf("sc%d: abort phase=0x%x, ssts=0x%x, ints=0x%x\n", 424 1.13 tsutsui hs->sc_ctlr, hd->scsi_psns, hd->scsi_ssts, hd->scsi_ints); 425 1.1 tsutsui 426 1.16 christos if (hd->scsi_ints != 0) 427 1.17 jakllsch /* write register value back to register */ 428 1.16 christos hd->scsi_ints = hd->scsi_ints; 429 1.16 christos 430 1.1 tsutsui if (hd->scsi_psns == 0 || (hd->scsi_ssts & SSTS_INITIATOR) == 0) 431 1.1 tsutsui /* no longer connected to scsi target */ 432 1.1 tsutsui return; 433 1.1 tsutsui 434 1.1 tsutsui /* get the number of bytes remaining in current xfer + fudge */ 435 1.1 tsutsui len = (hd->scsi_tch << 16) | (hd->scsi_tcm << 8) | hd->scsi_tcl; 436 1.1 tsutsui 437 1.1 tsutsui /* for that many bus cycles, try to send an abort msg */ 438 1.13 tsutsui for (len += 1024; 439 1.13 tsutsui ((hd->scsi_ssts & SSTS_INITIATOR)) != 0 && --len >= 0;) { 440 1.1 tsutsui hd->scsi_scmd = SCMD_SET_ATN; 441 1.1 tsutsui 442 1.1 tsutsui while ((hd->scsi_psns & PSNS_REQ) == 0) { 443 1.10 tsutsui if ((hd->scsi_ssts & SSTS_INITIATOR) == 0) 444 1.1 tsutsui goto out; 445 1.1 tsutsui DELAY(1); 446 1.1 tsutsui } 447 1.1 tsutsui 448 1.1 tsutsui if ((hd->scsi_psns & PHASE) == MESG_OUT_PHASE) 449 1.1 tsutsui hd->scsi_scmd = SCMD_RST_ATN; 450 1.1 tsutsui hd->scsi_pctl = hs->sc_phase = hd->scsi_psns & PHASE; 451 1.1 tsutsui 452 1.1 tsutsui if (hd->scsi_psns & PHASE_IO) { 453 1.1 tsutsui /* one of the input phases - read & discard a byte */ 454 1.1 tsutsui hd->scsi_scmd = SCMD_SET_ACK; 455 1.13 tsutsui while ((hd->scsi_psns & PSNS_REQ) != 0) 456 1.1 tsutsui DELAY(1); 457 1.11 tsutsui (void)hd->scsi_temp; 458 1.1 tsutsui } else { 459 1.1 tsutsui /* one of the output phases - send an abort msg */ 460 1.1 tsutsui hd->scsi_temp = MSG_ABORT; 461 1.1 tsutsui hd->scsi_scmd = SCMD_SET_ACK; 462 1.13 tsutsui while ((hd->scsi_psns & PSNS_REQ) != 0) 463 1.1 tsutsui DELAY(1); 464 1.1 tsutsui } 465 1.1 tsutsui 466 1.1 tsutsui hd->scsi_scmd = SCMD_RST_ACK; 467 1.1 tsutsui } 468 1.1 tsutsui out: 469 1.1 tsutsui /* 470 1.1 tsutsui * Either the abort was successful & the bus is disconnected or 471 1.1 tsutsui * the device didn't listen. If the latter, announce the problem. 472 1.1 tsutsui * Either way, reset the card & the SPC. 473 1.1 tsutsui */ 474 1.1 tsutsui if (len < 0 && hs) 475 1.1 tsutsui printf("sc%d: abort failed. phase=0x%x, ssts=0x%x\n", 476 1.13 tsutsui hs->sc_ctlr, hd->scsi_psns, hd->scsi_ssts); 477 1.1 tsutsui } 478 1.1 tsutsui 479 1.1 tsutsui 480 1.1 tsutsui /* 481 1.1 tsutsui * SCSI Command Handler 482 1.1 tsutsui */ 483 1.1 tsutsui 484 1.1 tsutsui int 485 1.9 tsutsui scsi_test_unit_rdy(int ctlr, int target, int lun) 486 1.1 tsutsui { 487 1.1 tsutsui static struct scsi_cdb6 cdb = { CMD_TEST_UNIT_READY }; 488 1.1 tsutsui int status; 489 1.1 tsutsui volatile int lock; 490 1.1 tsutsui 491 1.1 tsutsui #ifdef DEBUG 492 1.9 tsutsui printf("scsi_test_unit_rdy( %d, %d, %d): Start\n", ctlr, target, lun); 493 1.1 tsutsui #endif 494 1.1 tsutsui 495 1.9 tsutsui cdb.lun = lun; 496 1.1 tsutsui 497 1.13 tsutsui if (scrun(ctlr, target, (void *)&cdb, 6, NULL, 0, &lock) == 0) { 498 1.1 tsutsui #ifdef DEBUG 499 1.1 tsutsui printf("scsi_test_unit_rdy: Command Transfer Failed.\n"); 500 1.1 tsutsui #endif 501 1.10 tsutsui return -1; 502 1.1 tsutsui } 503 1.1 tsutsui 504 1.1 tsutsui while ((lock == SC_IN_PROGRESS) || (lock == SC_DISCONNECTED)) 505 1.1 tsutsui DELAY(10); 506 1.1 tsutsui 507 1.1 tsutsui status = scfinish(ctlr); 508 1.1 tsutsui 509 1.1 tsutsui if (lock == SC_IO_COMPLETE) { 510 1.1 tsutsui #ifdef DEBUG 511 1.1 tsutsui printf("scsi_test_unit_rdy: Status -- 0x%x\n", status); 512 1.1 tsutsui #endif 513 1.10 tsutsui return status; 514 1.1 tsutsui } else { 515 1.10 tsutsui return lock; 516 1.1 tsutsui } 517 1.1 tsutsui } 518 1.1 tsutsui 519 1.1 tsutsui int 520 1.12 tsutsui scsi_request_sense(int ctlr, int target, int lun, uint8_t *buf, 521 1.12 tsutsui unsigned int len) 522 1.1 tsutsui { 523 1.1 tsutsui static struct scsi_cdb6 cdb = { CMD_REQUEST_SENSE }; 524 1.1 tsutsui int status; 525 1.1 tsutsui volatile int lock; 526 1.1 tsutsui 527 1.1 tsutsui #ifdef DEBUG 528 1.1 tsutsui printf("scsi_request_sense: Start\n"); 529 1.1 tsutsui #endif 530 1.1 tsutsui 531 1.7 tsutsui /* Request Sense */ 532 1.7 tsutsui /* Additional Sens Length*/ 533 1.7 tsutsui /* cdbAllocation Length */ 534 1.7 tsutsui /* */ 535 1.1 tsutsui 536 1.7 tsutsui /* Addtional Sens Field */ 537 1.7 tsutsui /* len */ 538 1.1 tsutsui 539 1.9 tsutsui cdb.lun = lun; 540 1.1 tsutsui cdb.len = len; 541 1.1 tsutsui 542 1.13 tsutsui if (scrun(ctlr, target, (void *)&cdb, 6, buf, len, &lock) == 0) { 543 1.1 tsutsui #ifdef DEBUG 544 1.1 tsutsui printf("scsi_request_sense: Command Transfer Failed.\n"); 545 1.1 tsutsui #endif 546 1.10 tsutsui return -1; 547 1.1 tsutsui } 548 1.1 tsutsui 549 1.1 tsutsui while ((lock == SC_IN_PROGRESS) || (lock == SC_DISCONNECTED)) 550 1.1 tsutsui DELAY(10); 551 1.1 tsutsui 552 1.1 tsutsui status = scfinish(ctlr); 553 1.1 tsutsui 554 1.1 tsutsui if (lock == SC_IO_COMPLETE) { 555 1.1 tsutsui #ifdef DEBUG 556 1.1 tsutsui printf("scsi_request_sense: Status -- 0x%x\n", status); 557 1.1 tsutsui #endif 558 1.10 tsutsui return status; 559 1.1 tsutsui } else { 560 1.10 tsutsui return lock; 561 1.1 tsutsui } 562 1.1 tsutsui } 563 1.1 tsutsui 564 1.1 tsutsui int 565 1.9 tsutsui scsi_immed_command(int ctlr, int target, int lun, struct scsi_generic_cdb *cdb, 566 1.12 tsutsui uint8_t *buf, unsigned int len) 567 1.1 tsutsui { 568 1.1 tsutsui int status; 569 1.1 tsutsui volatile int lock; 570 1.1 tsutsui 571 1.1 tsutsui #ifdef DEBUG 572 1.1 tsutsui printf("scsi_immed_command( %d, %d, %d, cdb(%d), buf, %d): Start\n", 573 1.13 tsutsui ctlr, target, lun, cdb->len, len); 574 1.1 tsutsui #endif 575 1.1 tsutsui 576 1.9 tsutsui cdb->cdb[1] |= lun << 5; 577 1.1 tsutsui 578 1.13 tsutsui if (scrun(ctlr, target, (void *)&cdb->cdb[0], cdb->len, buf, len, 579 1.13 tsutsui &lock) == 0) { 580 1.1 tsutsui #ifdef DEBUG 581 1.1 tsutsui printf("scsi_immed_command: Command Transfer Failed.\n"); 582 1.1 tsutsui #endif 583 1.10 tsutsui return -1; 584 1.1 tsutsui } 585 1.1 tsutsui 586 1.1 tsutsui while ((lock == SC_IN_PROGRESS) || (lock == SC_DISCONNECTED)) 587 1.1 tsutsui DELAY(10); 588 1.1 tsutsui 589 1.1 tsutsui status = scfinish(ctlr); 590 1.1 tsutsui 591 1.1 tsutsui if (lock == SC_IO_COMPLETE) { 592 1.1 tsutsui #ifdef DEBUG 593 1.1 tsutsui printf("scsi_immed_command: Status -- 0x%x\n", status); 594 1.1 tsutsui #endif 595 1.10 tsutsui return status; 596 1.1 tsutsui } else { 597 1.10 tsutsui return lock; 598 1.1 tsutsui } 599 1.1 tsutsui } 600 1.1 tsutsui 601 1.1 tsutsui int 602 1.9 tsutsui scsi_format_unit(int ctlr, int target, int lun) 603 1.1 tsutsui { 604 1.1 tsutsui static struct scsi_cdb6 cdb = { CMD_FORMAT_UNIT, 0, 0, 0, 0, 0 }; 605 1.1 tsutsui int status; 606 1.1 tsutsui volatile int lock; 607 1.1 tsutsui #ifdef DEBUG 608 1.1 tsutsui int count = 0; 609 1.1 tsutsui #endif 610 1.1 tsutsui 611 1.1 tsutsui #ifdef DEBUG 612 1.9 tsutsui printf("scsi_format_unit( %d, %d, %d): Start\n", ctlr, target, lun); 613 1.1 tsutsui #endif 614 1.1 tsutsui 615 1.9 tsutsui cdb.lun = lun; 616 1.1 tsutsui 617 1.13 tsutsui if (scrun(ctlr, target, (void *)&cdb, 6, NULL, 0, &lock) == 0) { 618 1.1 tsutsui #ifdef DEBUG 619 1.1 tsutsui printf("scsi_format_unit: Command Transfer Failed.\n"); 620 1.1 tsutsui #endif 621 1.10 tsutsui return -1; 622 1.1 tsutsui } 623 1.1 tsutsui 624 1.1 tsutsui while ((lock == SC_IN_PROGRESS) || (lock == SC_DISCONNECTED)) { 625 1.1 tsutsui DELAY(1000000); 626 1.1 tsutsui #ifdef DEBUG 627 1.1 tsutsui if ((++count % 60) == 0) 628 1.1 tsutsui printf("scsi_format_unit: %d\n", count / 60); 629 1.1 tsutsui #endif 630 1.1 tsutsui } 631 1.1 tsutsui 632 1.1 tsutsui status = scfinish(ctlr); 633 1.1 tsutsui 634 1.1 tsutsui if (lock == SC_IO_COMPLETE) { 635 1.1 tsutsui #ifdef DEBUG 636 1.1 tsutsui printf("scsi_format_unit: Status -- 0x%x\n", status); 637 1.1 tsutsui #endif 638 1.10 tsutsui return status; 639 1.1 tsutsui } else { 640 1.10 tsutsui return lock; 641 1.1 tsutsui } 642 1.1 tsutsui } 643 1.1 tsutsui 644 1.1 tsutsui 645 1.1 tsutsui /* 646 1.1 tsutsui * Interrupt Routine 647 1.1 tsutsui */ 648 1.1 tsutsui 649 1.1 tsutsui int 650 1.1 tsutsui scintr(void) 651 1.1 tsutsui { 652 1.1 tsutsui struct scsi_softc *hs; 653 1.1 tsutsui struct scsidevice *hd; 654 1.12 tsutsui uint8_t ints, temp; 655 1.1 tsutsui int i; 656 1.12 tsutsui uint8_t *buf; 657 1.1 tsutsui int len; 658 1.1 tsutsui 659 1.1 tsutsui for (i = 0; i < NSC; i++) { 660 1.1 tsutsui hs = &scsi_softc[i]; 661 1.9 tsutsui hd = hs->sc_spc; 662 1.1 tsutsui if ((ints = hd->scsi_ints) != 0) 663 1.1 tsutsui goto get_intr; 664 1.1 tsutsui } 665 1.1 tsutsui 666 1.19 andvar /* Unknown interrupt occurred */ 667 1.1 tsutsui return -1; 668 1.1 tsutsui 669 1.1 tsutsui 670 1.1 tsutsui /* 671 1.1 tsutsui * Interrupt 672 1.1 tsutsui */ 673 1.1 tsutsui 674 1.1 tsutsui get_intr: 675 1.1 tsutsui #ifdef DEBUG 676 1.1 tsutsui printf("scintr: INTS 0x%x, SSTS 0x%x, PCTL 0x%x, PSNS 0x%x 0x%x\n", 677 1.13 tsutsui ints, hd->scsi_ssts, hd->scsi_pctl, hd->scsi_psns, hs->sc_phase); 678 1.1 tsutsui #endif 679 1.1 tsutsui if (ints & INTS_RESEL) { 680 1.1 tsutsui if (hs->sc_phase == BUS_FREE_PHASE) { 681 1.1 tsutsui temp = hd->scsi_temp & ~(1 << SCSI_ID); 682 1.1 tsutsui for (i = 0; temp != 1; i++) { 683 1.1 tsutsui temp >>= 1; 684 1.1 tsutsui } 685 1.1 tsutsui hs->sc_target = i; 686 1.1 tsutsui *(hs->sc_lock) = SC_IN_PROGRESS; 687 1.4 tsutsui } else 688 1.1 tsutsui goto abort; 689 1.1 tsutsui } else if (ints & INTS_DISCON) { 690 1.10 tsutsui if ((hs->sc_msg[0] == MSG_CMD_COMPLETE) || 691 1.10 tsutsui (hs->sc_msg[0] == MSG_DISCONNECT)) { 692 1.1 tsutsui hs->sc_phase = BUS_FREE_PHASE; 693 1.1 tsutsui hs->sc_target = SCSI_ID; 694 1.13 tsutsui if (hs->sc_msg[0] == MSG_CMD_COMPLETE) { 695 1.1 tsutsui /* SCSI IO complete */ 696 1.1 tsutsui *(hs->sc_lock) = SC_IO_COMPLETE; 697 1.13 tsutsui } else { 698 1.13 tsutsui /* Disconnected from Target */ 699 1.1 tsutsui *(hs->sc_lock) = SC_DISCONNECTED; 700 1.13 tsutsui } 701 1.1 tsutsui hd->scsi_ints = ints; 702 1.1 tsutsui return 0; 703 1.1 tsutsui } else 704 1.1 tsutsui goto abort; 705 1.1 tsutsui } else if (ints & INTS_CMD_DONE) { 706 1.1 tsutsui if (hs->sc_phase == BUS_FREE_PHASE) 707 1.1 tsutsui goto abort; 708 1.1 tsutsui else if (hs->sc_phase == MESG_IN_PHASE) { 709 1.1 tsutsui hd->scsi_scmd = SCMD_RST_ACK; 710 1.1 tsutsui hd->scsi_ints = ints; 711 1.1 tsutsui hs->sc_phase = hd->scsi_psns & PHASE; 712 1.1 tsutsui return 0; 713 1.1 tsutsui } 714 1.1 tsutsui if (hs->sc_flags & SC_SEL_TIMEOUT) 715 1.1 tsutsui hs->sc_flags &= ~SC_SEL_TIMEOUT; 716 1.1 tsutsui } else if (ints & INTS_SRV_REQ) { 717 1.1 tsutsui if (hs->sc_phase != MESG_IN_PHASE) 718 1.1 tsutsui goto abort; 719 1.1 tsutsui } else if (ints & INTS_TIMEOUT) { 720 1.1 tsutsui if (hs->sc_phase == ARB_SEL_PHASE) { 721 1.1 tsutsui if (hs->sc_flags & SC_SEL_TIMEOUT) { 722 1.1 tsutsui hs->sc_flags &= ~SC_SEL_TIMEOUT; 723 1.1 tsutsui hs->sc_phase = BUS_FREE_PHASE; 724 1.1 tsutsui hs->sc_target = SCSI_ID; 725 1.13 tsutsui /* Such SCSI Device is not connected. */ 726 1.1 tsutsui *(hs->sc_lock) = SC_DEV_NOT_FOUND; 727 1.1 tsutsui hd->scsi_ints = ints; 728 1.1 tsutsui return 0; 729 1.1 tsutsui } else { 730 1.1 tsutsui /* wait more 250 usec */ 731 1.1 tsutsui hs->sc_flags |= SC_SEL_TIMEOUT; 732 1.1 tsutsui hd->scsi_temp = 0; 733 1.1 tsutsui hd->scsi_tch = 0; 734 1.1 tsutsui hd->scsi_tcm = 0x06; 735 1.1 tsutsui hd->scsi_tcl = 0x40; 736 1.1 tsutsui hd->scsi_ints = ints; 737 1.1 tsutsui return 0; 738 1.1 tsutsui } 739 1.1 tsutsui } else 740 1.1 tsutsui goto abort; 741 1.1 tsutsui } else 742 1.1 tsutsui goto abort; 743 1.1 tsutsui 744 1.1 tsutsui hd->scsi_ints = ints; 745 1.1 tsutsui 746 1.1 tsutsui /* 747 1.1 tsutsui * Next SCSI Transfer 748 1.1 tsutsui */ 749 1.1 tsutsui 750 1.1 tsutsui while ((hd->scsi_psns & PSNS_REQ) == 0) { 751 1.1 tsutsui DELAY(1); 752 1.1 tsutsui } 753 1.1 tsutsui 754 1.1 tsutsui hs->sc_phase = hd->scsi_psns & PHASE; 755 1.1 tsutsui 756 1.10 tsutsui if ((hs->sc_phase == DATA_OUT_PHASE) || 757 1.10 tsutsui (hs->sc_phase == DATA_IN_PHASE)) { 758 1.1 tsutsui len = hs->sc_len; 759 1.1 tsutsui buf = hs->sc_buf; 760 1.1 tsutsui } else if (hs->sc_phase == CMD_PHASE) { 761 1.1 tsutsui len = hs->sc_cdblen; 762 1.1 tsutsui buf = hs->sc_cdb; 763 1.1 tsutsui } else if (hs->sc_phase == STATUS_PHASE) { 764 1.1 tsutsui len = 1; 765 1.1 tsutsui buf = &hs->sc_stat; 766 1.1 tsutsui } else { 767 1.1 tsutsui len = 1; 768 1.1 tsutsui buf = hs->sc_msg; 769 1.1 tsutsui } 770 1.1 tsutsui 771 1.1 tsutsui ixfer_start(hd, len, hs->sc_phase, 0); 772 1.1 tsutsui if (hs->sc_phase & PHASE_IO) 773 1.1 tsutsui ixfer_in(hd, len, buf); 774 1.1 tsutsui else 775 1.1 tsutsui ixfer_out(hd, len, buf); 776 1.1 tsutsui 777 1.1 tsutsui return 0; 778 1.1 tsutsui 779 1.1 tsutsui /* 780 1.1 tsutsui * SCSI Abort 781 1.1 tsutsui */ 782 1.1 tsutsui abort: 783 1.1 tsutsui /* SCSI IO failed */ 784 1.9 tsutsui scabort(hs); 785 1.1 tsutsui hd->scsi_ints = ints; 786 1.1 tsutsui *(hs->sc_lock) = SC_IO_FAILED; 787 1.1 tsutsui return -1; 788 1.1 tsutsui } 789