1 1.10 rin /* $NetBSD: siop.c,v 1.10 2024/07/02 05:34:08 rin Exp $ */ 2 1.1 kiyohara /* 3 1.1 kiyohara * Copyright (c) 2010 KIYOHARA Takashi 4 1.1 kiyohara * All rights reserved. 5 1.1 kiyohara * 6 1.1 kiyohara * Redistribution and use in source and binary forms, with or without 7 1.1 kiyohara * modification, are permitted provided that the following conditions 8 1.1 kiyohara * are met: 9 1.1 kiyohara * 1. Redistributions of source code must retain the above copyright 10 1.1 kiyohara * notice, this list of conditions and the following disclaimer. 11 1.1 kiyohara * 2. Redistributions in binary form must reproduce the above copyright 12 1.1 kiyohara * notice, this list of conditions and the following disclaimer in the 13 1.1 kiyohara * documentation and/or other materials provided with the distribution. 14 1.1 kiyohara * 15 1.1 kiyohara * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 1.1 kiyohara * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 1.1 kiyohara * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 1.1 kiyohara * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 19 1.1 kiyohara * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 1.1 kiyohara * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 1.1 kiyohara * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 1.1 kiyohara * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 23 1.1 kiyohara * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 24 1.1 kiyohara * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 1.1 kiyohara * POSSIBILITY OF SUCH DAMAGE. 26 1.1 kiyohara */ 27 1.1 kiyohara 28 1.1 kiyohara #include <lib/libsa/stand.h> 29 1.1 kiyohara #include <lib/libkern/libkern.h> 30 1.1 kiyohara 31 1.1 kiyohara #include <dev/microcode/siop/siop.out> 32 1.1 kiyohara 33 1.1 kiyohara #include "boot.h" 34 1.1 kiyohara #include "sdvar.h" 35 1.1 kiyohara 36 1.1 kiyohara #define SIOP_DEFAULT_TARGET 7 37 1.1 kiyohara 38 1.1 kiyohara #define ALLOC(T, A) \ 39 1.1 kiyohara (T *)(((uint32_t)alloc(sizeof(T) + (A)) + (A)) & ~((A) - 1)) 40 1.1 kiyohara #define VTOPHYS(va) (uint32_t)(va) 41 1.1 kiyohara #define DEVTOV(pa) (uint32_t)(pa) 42 1.1 kiyohara #define wbinv(adr, siz) _wbinv(VTOPHYS(adr), (uint32_t)(siz)) 43 1.1 kiyohara #define inv(adr, siz) _inv(VTOPHYS(adr), (uint32_t)(siz)) 44 1.1 kiyohara 45 1.1 kiyohara /* 53c810 supports little endian */ 46 1.1 kiyohara #define htoc32(x) htole32(x) 47 1.1 kiyohara #define ctoh32(x) le32toh(x) 48 1.1 kiyohara 49 1.1 kiyohara static void siop_pci_reset(int); 50 1.1 kiyohara 51 1.1 kiyohara static void siop_setuptables(struct siop_adapter *, struct siop_xfer *, 52 1.1 kiyohara struct scsi_xfer *); 53 1.1 kiyohara static void siop_ma(struct siop_adapter *, struct scsi_xfer *); 54 1.1 kiyohara static void siop_sdp(struct siop_adapter *, struct siop_xfer *, 55 1.1 kiyohara struct scsi_xfer *, int); 56 1.1 kiyohara static void siop_update_resid(struct siop_adapter *, struct siop_xfer *, 57 1.1 kiyohara struct scsi_xfer *, int); 58 1.1 kiyohara 59 1.1 kiyohara static int siop_intr(struct siop_adapter *); 60 1.1 kiyohara static void siop_scsicmd_end(struct siop_adapter *, struct scsi_xfer *); 61 1.1 kiyohara static int siop_scsi_request(struct siop_adapter *, struct scsi_xfer *); 62 1.1 kiyohara static void siop_start(struct siop_adapter *, struct scsi_xfer *); 63 1.1 kiyohara static void siop_xfer_setup(struct siop_xfer *, void *); 64 1.1 kiyohara 65 1.1 kiyohara static int siop_add_reselsw(struct siop_adapter *, int, int); 66 1.1 kiyohara static void siop_update_scntl3(struct siop_adapter *, int, int); 67 1.1 kiyohara 68 1.9 rin static int _scsi_inquire(struct siop_adapter *, int, int, int, void *); 69 1.1 kiyohara static void scsi_request_sense(struct siop_adapter *, struct scsi_xfer *); 70 1.1 kiyohara static int scsi_interpret_sense(struct siop_adapter *, struct scsi_xfer *); 71 1.1 kiyohara static int scsi_probe(struct siop_adapter *); 72 1.1 kiyohara 73 1.1 kiyohara static struct siop_adapter adapt; 74 1.1 kiyohara 75 1.1 kiyohara 76 1.1 kiyohara static void 77 1.1 kiyohara siop_pci_reset(int addr) 78 1.1 kiyohara { 79 1.1 kiyohara int dmode, ctest5; 80 1.1 kiyohara const int maxburst = 4; /* 53c810 */ 81 1.1 kiyohara 82 1.1 kiyohara dmode = readb(addr + SIOP_DMODE); 83 1.1 kiyohara 84 1.1 kiyohara ctest5 = readb(addr + SIOP_CTEST5); 85 1.1 kiyohara writeb(addr + SIOP_CTEST4, readb(addr + SIOP_CTEST4) & ~CTEST4_BDIS); 86 1.1 kiyohara ctest5 &= ~CTEST5_BBCK; 87 1.1 kiyohara ctest5 |= (maxburst - 1) & CTEST5_BBCK; 88 1.1 kiyohara writeb(addr + SIOP_CTEST5, ctest5); 89 1.1 kiyohara 90 1.1 kiyohara dmode |= DMODE_ERL; 91 1.1 kiyohara dmode &= ~DMODE_BL_MASK; 92 1.1 kiyohara dmode |= ((maxburst - 1) << DMODE_BL_SHIFT) & DMODE_BL_MASK; 93 1.1 kiyohara writeb(addr + SIOP_DMODE, dmode); 94 1.1 kiyohara } 95 1.1 kiyohara 96 1.1 kiyohara 97 1.1 kiyohara static void 98 1.1 kiyohara siop_setuptables(struct siop_adapter *adp, struct siop_xfer *xfer, 99 1.1 kiyohara struct scsi_xfer *xs) 100 1.1 kiyohara { 101 1.1 kiyohara int msgoffset = 1; 102 1.1 kiyohara 103 1.1 kiyohara xfer->siop_tables.id = 104 1.1 kiyohara htoc32((adp->clock_div << 24) | (xs->target << 16)); 105 1.1 kiyohara memset(xfer->siop_tables.msg_out, 0, sizeof(xfer->siop_tables.msg_out)); 106 1.1 kiyohara /* request sense doesn't disconnect */ 107 1.1 kiyohara if (xs->cmd->opcode == SCSI_REQUEST_SENSE) 108 1.1 kiyohara xfer->siop_tables.msg_out[0] = MSG_IDENTIFY(xs->lun, 0); 109 1.1 kiyohara else 110 1.1 kiyohara xfer->siop_tables.msg_out[0] = MSG_IDENTIFY(xs->lun, 1); 111 1.1 kiyohara 112 1.1 kiyohara xfer->siop_tables.t_msgout.count = htoc32(msgoffset); 113 1.1 kiyohara xfer->siop_tables.status = 114 1.1 kiyohara htoc32(SCSI_SIOP_NOSTATUS); /* set invalid status */ 115 1.1 kiyohara 116 1.1 kiyohara xfer->siop_tables.cmd.count = htoc32(xs->cmdlen); 117 1.1 kiyohara xfer->siop_tables.cmd.addr = htoc32(local_to_PCI((u_long)xs->cmd)); 118 1.1 kiyohara if (xs->datalen != 0) { 119 1.1 kiyohara xfer->siop_tables.data[0].count = htoc32(xs->datalen); 120 1.1 kiyohara xfer->siop_tables.data[0].addr = 121 1.1 kiyohara htoc32(local_to_PCI((u_long)xs->data)); 122 1.1 kiyohara } 123 1.1 kiyohara } 124 1.1 kiyohara 125 1.1 kiyohara static void 126 1.1 kiyohara siop_ma(struct siop_adapter *adp, struct scsi_xfer *xs) 127 1.1 kiyohara { 128 1.1 kiyohara int offset, dbc; 129 1.1 kiyohara 130 1.1 kiyohara /* 131 1.1 kiyohara * compute how much of the current table didn't get handled when 132 1.1 kiyohara * a phase mismatch occurs 133 1.1 kiyohara */ 134 1.1 kiyohara if (xs->datalen == 0) 135 1.1 kiyohara return; /* no valid data transfer */ 136 1.1 kiyohara 137 1.1 kiyohara offset = readb(adp->addr + SIOP_SCRATCHA + 1); 138 1.1 kiyohara if (offset >= SIOP_NSG) { 139 1.1 kiyohara printf("bad offset in siop_sdp (%d)\n", offset); 140 1.1 kiyohara return; 141 1.1 kiyohara } 142 1.1 kiyohara dbc = readl(adp->addr + SIOP_DBC) & 0x00ffffff; 143 1.1 kiyohara xs->resid = dbc; 144 1.1 kiyohara } 145 1.1 kiyohara 146 1.1 kiyohara static void 147 1.1 kiyohara siop_sdp(struct siop_adapter *adp, struct siop_xfer *xfer, struct scsi_xfer *xs, 148 1.1 kiyohara int offset) 149 1.1 kiyohara { 150 1.1 kiyohara 151 1.1 kiyohara if (xs->datalen == 0) 152 1.1 kiyohara return; /* no data pointers to save */ 153 1.1 kiyohara 154 1.1 kiyohara /* 155 1.1 kiyohara * offset == SIOP_NSG may be a valid condition if we get a Save data 156 1.1 kiyohara * pointer when the xfer is done. Just ignore the Save data pointer 157 1.1 kiyohara * in this case 158 1.1 kiyohara */ 159 1.1 kiyohara if (offset == SIOP_NSG) 160 1.1 kiyohara return; 161 1.1 kiyohara /* 162 1.1 kiyohara * Save data pointer. We do this by adjusting the tables to point 163 1.4 andvar * at the beginning of the data not yet transferred. 164 1.4 andvar * offset points to the first table with untransferred data. 165 1.1 kiyohara */ 166 1.1 kiyohara 167 1.1 kiyohara /* 168 1.4 andvar * before doing that we decrease resid from the amount of data which 169 1.4 andvar * has been transferred. 170 1.1 kiyohara */ 171 1.1 kiyohara siop_update_resid(adp, xfer, xs, offset); 172 1.1 kiyohara 173 1.1 kiyohara #if 0 174 1.1 kiyohara /* 175 1.1 kiyohara * First let see if we have a resid from a phase mismatch. If so, 176 1.4 andvar * we have to adjust the table at offset to remove transferred data. 177 1.1 kiyohara */ 178 1.1 kiyohara if (siop_cmd->flags & CMDFL_RESID) { 179 1.1 kiyohara scr_table_t *table; 180 1.1 kiyohara 181 1.1 kiyohara siop_cmd->flags &= ~CMDFL_RESID; 182 1.1 kiyohara table = &xfer->siop_tables.data[offset]; 183 1.5 andvar /* "cut" already transferred data from this table */ 184 1.1 kiyohara table->addr = 185 1.1 kiyohara htoc32(ctoh32(table->addr) + ctoh32(table->count) - 186 1.1 kiyohara siop_cmd->resid); 187 1.1 kiyohara table->count = htoc32(siop_cmd->resid); 188 1.1 kiyohara } 189 1.1 kiyohara #endif 190 1.1 kiyohara 191 1.1 kiyohara /* 192 1.4 andvar * now we can remove entries which have been transferred. 193 1.4 andvar * We just move the entries with data left at the beginning of the 194 1.1 kiyohara * tables 195 1.1 kiyohara */ 196 1.1 kiyohara memmove(xfer->siop_tables.data, &xfer->siop_tables.data[offset], 197 1.1 kiyohara (SIOP_NSG - offset) * sizeof(scr_table_t)); 198 1.1 kiyohara } 199 1.1 kiyohara 200 1.1 kiyohara static void 201 1.1 kiyohara siop_update_resid(struct siop_adapter *adp, struct siop_xfer *xfer, 202 1.1 kiyohara struct scsi_xfer *xs, int offset) 203 1.1 kiyohara { 204 1.1 kiyohara int i; 205 1.1 kiyohara 206 1.1 kiyohara if (xs->datalen == 0) 207 1.1 kiyohara return; /* no data to transfer */ 208 1.1 kiyohara 209 1.1 kiyohara /* 210 1.1 kiyohara * update resid. First account for the table entries which have 211 1.1 kiyohara * been fully completed. 212 1.1 kiyohara */ 213 1.1 kiyohara for (i = 0; i < offset; i++) 214 1.1 kiyohara xs->resid -= ctoh32(xfer->siop_tables.data[i].count); 215 1.1 kiyohara #if 0 216 1.1 kiyohara /* 217 1.1 kiyohara * if CMDFL_RESID is set, the last table (pointed by offset) is a 218 1.6 andvar * partial transfers. If not, offset points to the entry following 219 1.1 kiyohara * the last full transfer. 220 1.1 kiyohara */ 221 1.1 kiyohara if (siop_cmd->flags & CMDFL_RESID) { 222 1.1 kiyohara scr_table_t *table = &xfer->siop_tables.data[offset]; 223 1.1 kiyohara 224 1.1 kiyohara xs->resid -= ctoh32(table->count) - xs->resid; 225 1.1 kiyohara } 226 1.1 kiyohara #endif 227 1.1 kiyohara } 228 1.1 kiyohara 229 1.1 kiyohara 230 1.1 kiyohara #define CALL_SCRIPT(ent) writel(adp->addr + SIOP_DSP, scriptaddr + ent); 231 1.1 kiyohara 232 1.1 kiyohara static int 233 1.1 kiyohara siop_intr(struct siop_adapter *adp) 234 1.1 kiyohara { 235 1.1 kiyohara struct siop_xfer *siop_xfer = NULL; 236 1.1 kiyohara struct scsi_xfer *xs = NULL; 237 1.1 kiyohara u_long scriptaddr = local_to_PCI((u_long)adp->script); 238 1.1 kiyohara int offset, target, lun, tag, restart = 0, need_reset = 0; 239 1.1 kiyohara uint32_t dsa, irqcode; 240 1.1 kiyohara uint16_t sist; 241 1.2 mrg uint8_t dstat = 0, sstat1, istat; 242 1.1 kiyohara 243 1.1 kiyohara istat = readb(adp->addr + SIOP_ISTAT); 244 1.1 kiyohara if ((istat & (ISTAT_INTF | ISTAT_DIP | ISTAT_SIP)) == 0) 245 1.1 kiyohara return 0; 246 1.1 kiyohara if (istat & ISTAT_INTF) { 247 1.1 kiyohara printf("INTRF\n"); 248 1.1 kiyohara writeb(adp->addr + SIOP_ISTAT, ISTAT_INTF); 249 1.1 kiyohara } 250 1.1 kiyohara if ((istat & (ISTAT_DIP | ISTAT_SIP | ISTAT_ABRT)) == 251 1.1 kiyohara (ISTAT_DIP | ISTAT_ABRT)) 252 1.1 kiyohara /* clear abort */ 253 1.1 kiyohara writeb(adp->addr + SIOP_ISTAT, 0); 254 1.1 kiyohara /* use DSA to find the current siop_cmd */ 255 1.1 kiyohara dsa = readl(adp->addr + SIOP_DSA); 256 1.1 kiyohara if (dsa >= local_to_PCI((u_long)adp->xfer) && 257 1.1 kiyohara dsa < local_to_PCI((u_long)adp->xfer) + SIOP_TABLE_SIZE) { 258 1.1 kiyohara dsa -= local_to_PCI((u_long)adp->xfer); 259 1.1 kiyohara siop_xfer = adp->xfer; 260 1.1 kiyohara _inv((u_long)siop_xfer, sizeof(*siop_xfer)); 261 1.1 kiyohara 262 1.1 kiyohara xs = adp->xs; 263 1.1 kiyohara } 264 1.1 kiyohara 265 1.1 kiyohara if (istat & ISTAT_DIP) 266 1.1 kiyohara dstat = readb(adp->addr + SIOP_DSTAT); 267 1.1 kiyohara if (istat & ISTAT_SIP) { 268 1.1 kiyohara if (istat & ISTAT_DIP) 269 1.1 kiyohara delay(10); 270 1.1 kiyohara /* 271 1.1 kiyohara * Can't read sist0 & sist1 independently, or we have to 272 1.1 kiyohara * insert delay 273 1.1 kiyohara */ 274 1.1 kiyohara sist = readw(adp->addr + SIOP_SIST0); 275 1.1 kiyohara sstat1 = readb(adp->addr + SIOP_SSTAT1); 276 1.1 kiyohara 277 1.1 kiyohara if ((sist & SIST0_MA) && need_reset == 0) { 278 1.1 kiyohara if (siop_xfer) { 279 1.1 kiyohara int scratcha0; 280 1.1 kiyohara 281 1.1 kiyohara dstat = readb(adp->addr + SIOP_DSTAT); 282 1.1 kiyohara /* 283 1.1 kiyohara * first restore DSA, in case we were in a S/G 284 1.1 kiyohara * operation. 285 1.1 kiyohara */ 286 1.1 kiyohara writel(adp->addr + SIOP_DSA, 287 1.1 kiyohara local_to_PCI((u_long)siop_xfer)); 288 1.1 kiyohara scratcha0 = readb(adp->addr + SIOP_SCRATCHA); 289 1.1 kiyohara switch (sstat1 & SSTAT1_PHASE_MASK) { 290 1.1 kiyohara case SSTAT1_PHASE_STATUS: 291 1.1 kiyohara /* 292 1.1 kiyohara * previous phase may be aborted for any reason 293 1.1 kiyohara * ( for example, the target has less data to 294 1.1 kiyohara * transfer than requested). Compute resid and 295 1.1 kiyohara * just go to status, the command should 296 1.1 kiyohara * terminate. 297 1.1 kiyohara */ 298 1.1 kiyohara if (scratcha0 & A_flag_data) 299 1.1 kiyohara siop_ma(adp, xs); 300 1.1 kiyohara else if ((dstat & DSTAT_DFE) == 0) 301 1.1 kiyohara printf("PHASE STATUS: siop_clearfifo...\n"); 302 1.1 kiyohara // siop_clearfifo(adp); 303 1.1 kiyohara CALL_SCRIPT(Ent_status); 304 1.1 kiyohara return 1; 305 1.1 kiyohara case SSTAT1_PHASE_MSGIN: 306 1.1 kiyohara /* 307 1.1 kiyohara * target may be ready to disconnect 308 1.1 kiyohara * Compute resid which would be used later 309 1.1 kiyohara * if a save data pointer is needed. 310 1.1 kiyohara */ 311 1.1 kiyohara if (scratcha0 & A_flag_data) 312 1.1 kiyohara siop_ma(adp, xs); 313 1.1 kiyohara else if ((dstat & DSTAT_DFE) == 0) 314 1.1 kiyohara printf("PHASE MSGIN: siop_clearfifo...\n"); 315 1.1 kiyohara // siop_clearfifo(adp); 316 1.1 kiyohara writeb(adp->addr + SIOP_SCRATCHA, 317 1.1 kiyohara scratcha0 & ~A_flag_data); 318 1.1 kiyohara CALL_SCRIPT(Ent_msgin); 319 1.1 kiyohara return 1; 320 1.1 kiyohara } 321 1.1 kiyohara printf("unexpected phase mismatch %d\n", 322 1.1 kiyohara sstat1 & SSTAT1_PHASE_MASK); 323 1.1 kiyohara } else 324 1.1 kiyohara printf("phase mismatch without command\n"); 325 1.1 kiyohara need_reset = 1; 326 1.1 kiyohara } 327 1.1 kiyohara if (sist & (SIST1_STO << 8)) { 328 1.1 kiyohara /* selection time out, assume there's no device here */ 329 1.1 kiyohara if (siop_xfer) { 330 1.1 kiyohara xs->error = XS_SELTIMEOUT; 331 1.1 kiyohara goto end; 332 1.1 kiyohara } else 333 1.1 kiyohara printf("selection timeout without command\n"); 334 1.1 kiyohara } 335 1.1 kiyohara 336 1.1 kiyohara /* Else it's an unhandled exception (for now). */ 337 1.1 kiyohara printf("unhandled scsi interrupt," 338 1.1 kiyohara " sist=0x%x sstat1=0x%x DSA=0x%x DSP=0x%lx\n", 339 1.1 kiyohara sist, sstat1, dsa, 340 1.1 kiyohara readl(adp->addr + SIOP_DSP) - scriptaddr); 341 1.1 kiyohara if (siop_xfer) { 342 1.1 kiyohara xs->error = XS_SELTIMEOUT; 343 1.1 kiyohara goto end; 344 1.1 kiyohara } 345 1.1 kiyohara need_reset = 1; 346 1.1 kiyohara } 347 1.1 kiyohara if (need_reset) { 348 1.1 kiyohara reset: 349 1.1 kiyohara printf("XXXXX: fatal error, need reset the bus...\n"); 350 1.1 kiyohara return 1; 351 1.1 kiyohara } 352 1.1 kiyohara 353 1.1 kiyohara //scintr: 354 1.1 kiyohara if ((istat & ISTAT_DIP) && (dstat & DSTAT_SIR)) { /* script interrupt */ 355 1.1 kiyohara irqcode = readl(adp->addr + SIOP_DSPS); 356 1.1 kiyohara /* 357 1.1 kiyohara * no command, or an inactive command is only valid for a 358 1.1 kiyohara * reselect interrupt 359 1.1 kiyohara */ 360 1.1 kiyohara if ((irqcode & 0x80) == 0) { 361 1.1 kiyohara if (siop_xfer == NULL) { 362 1.1 kiyohara printf( 363 1.1 kiyohara "script interrupt 0x%x with invalid DSA\n", 364 1.1 kiyohara irqcode); 365 1.1 kiyohara goto reset; 366 1.1 kiyohara } 367 1.1 kiyohara } 368 1.1 kiyohara switch(irqcode) { 369 1.1 kiyohara case A_int_err: 370 1.1 kiyohara printf("error, DSP=0x%lx\n", 371 1.1 kiyohara readl(adp->addr + SIOP_DSP) - scriptaddr); 372 1.1 kiyohara if (xs) { 373 1.1 kiyohara xs->error = XS_SELTIMEOUT; 374 1.1 kiyohara goto end; 375 1.1 kiyohara } else { 376 1.1 kiyohara goto reset; 377 1.1 kiyohara } 378 1.1 kiyohara case A_int_reseltarg: 379 1.1 kiyohara printf("reselect with invalid target\n"); 380 1.1 kiyohara goto reset; 381 1.1 kiyohara case A_int_resellun: 382 1.1 kiyohara target = readb(adp->addr + SIOP_SCRATCHA) & 0xf; 383 1.1 kiyohara lun = readb(adp->addr + SIOP_SCRATCHA + 1); 384 1.1 kiyohara tag = readb(adp->addr + SIOP_SCRATCHA + 2); 385 1.1 kiyohara if (target != adp->xs->target || 386 1.1 kiyohara lun != adp->xs->lun || 387 1.1 kiyohara tag != 0) { 388 1.7 msaitoh printf("unknown resellun:" 389 1.1 kiyohara " target %d lun %d tag %d\n", 390 1.1 kiyohara target, lun, tag); 391 1.1 kiyohara goto reset; 392 1.1 kiyohara } 393 1.1 kiyohara siop_xfer = adp->xfer; 394 1.1 kiyohara dsa = local_to_PCI((u_long)siop_xfer); 395 1.1 kiyohara writel(adp->addr + SIOP_DSP, 396 1.1 kiyohara dsa + sizeof(struct siop_common_xfer) + 397 1.1 kiyohara Ent_ldsa_reload_dsa); 398 1.1 kiyohara _wbinv((u_long)siop_xfer, sizeof(*siop_xfer)); 399 1.1 kiyohara return 1; 400 1.1 kiyohara case A_int_reseltag: 401 1.1 kiyohara printf("reselect with invalid tag\n"); 402 1.1 kiyohara goto reset; 403 1.1 kiyohara case A_int_disc: 404 1.1 kiyohara offset = readb(adp->addr + SIOP_SCRATCHA + 1); 405 1.1 kiyohara siop_sdp(adp, siop_xfer, xs, offset); 406 1.1 kiyohara #if 0 407 1.1 kiyohara /* we start again with no offset */ 408 1.1 kiyohara siop_cmd->saved_offset = SIOP_NOOFFSET; 409 1.1 kiyohara #endif 410 1.1 kiyohara _wbinv((u_long)siop_xfer, sizeof(*siop_xfer)); 411 1.1 kiyohara CALL_SCRIPT(Ent_script_sched); 412 1.1 kiyohara return 1; 413 1.1 kiyohara case A_int_resfail: 414 1.1 kiyohara printf("reselect failed\n"); 415 1.1 kiyohara return 1; 416 1.1 kiyohara case A_int_done: 417 1.1 kiyohara if (xs == NULL) { 418 1.1 kiyohara printf("done without command, DSA=0x%lx\n", 419 1.1 kiyohara local_to_PCI((u_long)adp->xfer)); 420 1.1 kiyohara return 1; 421 1.1 kiyohara } 422 1.1 kiyohara /* update resid. */ 423 1.1 kiyohara offset = readb(adp->addr + SIOP_SCRATCHA + 1); 424 1.1 kiyohara #if 0 425 1.1 kiyohara /* 426 1.1 kiyohara * if we got a disconnect between the last data phase 427 1.1 kiyohara * and the status phase, offset will be 0. In this 428 1.1 kiyohara * case, siop_cmd->saved_offset will have the proper 429 1.1 kiyohara * value if it got updated by the controller 430 1.1 kiyohara */ 431 1.1 kiyohara if (offset == 0 && 432 1.1 kiyohara siop_cmd->saved_offset != SIOP_NOOFFSET) 433 1.1 kiyohara offset = siop_cmd->saved_offset; 434 1.1 kiyohara #endif 435 1.1 kiyohara siop_update_resid(adp, siop_xfer, xs, offset); 436 1.1 kiyohara goto end; 437 1.1 kiyohara default: 438 1.1 kiyohara printf("unknown irqcode %x\n", irqcode); 439 1.1 kiyohara if (xs) { 440 1.1 kiyohara xs->error = XS_SELTIMEOUT; 441 1.1 kiyohara goto end; 442 1.1 kiyohara } 443 1.1 kiyohara goto reset; 444 1.1 kiyohara } 445 1.1 kiyohara return 1; 446 1.1 kiyohara } 447 1.8 andvar /* We just shouldn't get there */ 448 1.1 kiyohara panic("siop_intr: I shouldn't be there !"); 449 1.1 kiyohara 450 1.1 kiyohara return 1; 451 1.1 kiyohara 452 1.1 kiyohara end: 453 1.1 kiyohara /* 454 1.1 kiyohara * restart the script now if command completed properly 455 1.1 kiyohara * Otherwise wait for siop_scsicmd_end(), we may need to cleanup the 456 1.1 kiyohara * queue 457 1.1 kiyohara */ 458 1.1 kiyohara xs->status = ctoh32(siop_xfer->siop_tables.status); 459 1.1 kiyohara if (xs->status == SCSI_OK) 460 1.1 kiyohara writel(adp->addr + SIOP_DSP, scriptaddr + Ent_script_sched); 461 1.1 kiyohara else 462 1.1 kiyohara restart = 1; 463 1.1 kiyohara siop_scsicmd_end(adp, xs); 464 1.1 kiyohara if (restart) 465 1.1 kiyohara writel(adp->addr + SIOP_DSP, scriptaddr + Ent_script_sched); 466 1.1 kiyohara 467 1.1 kiyohara return 1; 468 1.1 kiyohara } 469 1.1 kiyohara 470 1.1 kiyohara static void 471 1.1 kiyohara siop_scsicmd_end(struct siop_adapter *adp, struct scsi_xfer *xs) 472 1.1 kiyohara { 473 1.1 kiyohara 474 1.1 kiyohara switch(xs->status) { 475 1.1 kiyohara case SCSI_OK: 476 1.1 kiyohara xs->error = XS_NOERROR; 477 1.1 kiyohara break; 478 1.1 kiyohara case SCSI_BUSY: 479 1.1 kiyohara case SCSI_CHECK: 480 1.1 kiyohara case SCSI_QUEUE_FULL: 481 1.1 kiyohara xs->error = XS_BUSY; 482 1.1 kiyohara break; 483 1.1 kiyohara case SCSI_SIOP_NOCHECK: 484 1.1 kiyohara /* 485 1.1 kiyohara * don't check status, xs->error is already valid 486 1.1 kiyohara */ 487 1.1 kiyohara break; 488 1.1 kiyohara case SCSI_SIOP_NOSTATUS: 489 1.1 kiyohara /* 490 1.1 kiyohara * the status byte was not updated, cmd was 491 1.1 kiyohara * aborted 492 1.1 kiyohara */ 493 1.1 kiyohara xs->error = XS_SELTIMEOUT; 494 1.1 kiyohara break; 495 1.1 kiyohara default: 496 1.1 kiyohara printf("invalid status code %d\n", xs->status); 497 1.1 kiyohara xs->error = XS_DRIVER_STUFFUP; 498 1.1 kiyohara } 499 1.1 kiyohara _inv((u_long)xs->cmd, xs->cmdlen); 500 1.1 kiyohara if (xs->datalen != 0) 501 1.1 kiyohara _inv((u_long)xs->data, xs->datalen); 502 1.1 kiyohara xs->xs_status = XS_STS_DONE; 503 1.1 kiyohara } 504 1.1 kiyohara 505 1.1 kiyohara static int 506 1.1 kiyohara siop_scsi_request(struct siop_adapter *adp, struct scsi_xfer *xs) 507 1.1 kiyohara { 508 1.1 kiyohara void *xfer = adp->xfer; 509 1.1 kiyohara int timo, error; 510 1.1 kiyohara 511 1.1 kiyohara if (adp->sel_t != xs->target) { 512 1.1 kiyohara const int free_lo = __arraycount(siop_script); 513 1.1 kiyohara int i; 514 1.1 kiyohara void *scriptaddr = (void *)local_to_PCI((u_long)adp->script); 515 1.1 kiyohara 516 1.1 kiyohara if (adp->sel_t != -1) 517 1.1 kiyohara adp->script[Ent_resel_targ0 / 4 + adp->sel_t * 2] = 518 1.1 kiyohara htoc32(0x800c00ff); 519 1.1 kiyohara 520 1.1 kiyohara for (i = 0; i < __arraycount(lun_switch); i++) 521 1.1 kiyohara adp->script[free_lo + i] = htoc32(lun_switch[i]); 522 1.1 kiyohara adp->script[free_lo + E_abs_lunsw_return_Used[0]] = 523 1.1 kiyohara htoc32(scriptaddr + Ent_lunsw_return); 524 1.1 kiyohara 525 1.1 kiyohara siop_add_reselsw(adp, xs->target, free_lo); 526 1.1 kiyohara 527 1.1 kiyohara adp->sel_t = xs->target; 528 1.1 kiyohara } 529 1.1 kiyohara 530 1.1 kiyohara restart: 531 1.1 kiyohara 532 1.1 kiyohara siop_setuptables(adp, xfer, xs); 533 1.1 kiyohara 534 1.1 kiyohara /* load the DMA maps */ 535 1.1 kiyohara if (xs->datalen != 0) 536 1.1 kiyohara _inv((u_long)xs->data, xs->datalen); 537 1.1 kiyohara _wbinv((u_long)xs->cmd, xs->cmdlen); 538 1.1 kiyohara 539 1.1 kiyohara _wbinv((u_long)xfer, sizeof(struct siop_xfer)); 540 1.1 kiyohara siop_start(adp, xs); 541 1.1 kiyohara 542 1.1 kiyohara adp->xs = xs; 543 1.1 kiyohara timo = 0; 544 1.1 kiyohara while (!(xs->xs_status & XS_STS_DONE)) { 545 1.1 kiyohara delay(1000); 546 1.1 kiyohara siop_intr(adp); 547 1.1 kiyohara 548 1.1 kiyohara if (timo++ > 3000) { /* XXXX: 3sec */ 549 1.1 kiyohara printf("%s: timeout\n", __func__); 550 1.1 kiyohara return ETIMEDOUT; 551 1.1 kiyohara } 552 1.1 kiyohara } 553 1.1 kiyohara 554 1.1 kiyohara if (xs->error != XS_NOERROR) { 555 1.1 kiyohara if (xs->error == XS_BUSY || xs->status == SCSI_CHECK) 556 1.1 kiyohara scsi_request_sense(adp, xs); 557 1.1 kiyohara 558 1.1 kiyohara switch (xs->error) { 559 1.1 kiyohara case XS_SENSE: 560 1.1 kiyohara case XS_SHORTSENSE: 561 1.1 kiyohara error = scsi_interpret_sense(adp, xs); 562 1.1 kiyohara break; 563 1.1 kiyohara case XS_RESOURCE_SHORTAGE: 564 1.1 kiyohara printf("adapter resource shortage\n"); 565 1.1 kiyohara 566 1.1 kiyohara /* FALLTHROUGH */ 567 1.1 kiyohara case XS_BUSY: 568 1.1 kiyohara error = EBUSY; 569 1.1 kiyohara break; 570 1.1 kiyohara case XS_REQUEUE: 571 1.1 kiyohara printf("XXXX: requeue...\n"); 572 1.1 kiyohara error = ERESTART; 573 1.1 kiyohara break; 574 1.1 kiyohara case XS_SELTIMEOUT: 575 1.1 kiyohara case XS_TIMEOUT: 576 1.1 kiyohara error = EIO; 577 1.1 kiyohara break; 578 1.1 kiyohara case XS_RESET: 579 1.1 kiyohara error = EIO; 580 1.1 kiyohara break; 581 1.1 kiyohara case XS_DRIVER_STUFFUP: 582 1.1 kiyohara printf("generic HBA error\n"); 583 1.1 kiyohara error = EIO; 584 1.1 kiyohara break; 585 1.1 kiyohara default: 586 1.1 kiyohara printf("invalid return code from adapter: %d\n", 587 1.1 kiyohara xs->error); 588 1.1 kiyohara error = EIO; 589 1.1 kiyohara break; 590 1.1 kiyohara } 591 1.1 kiyohara if (error == ERESTART) { 592 1.1 kiyohara xs->error = XS_NOERROR; 593 1.1 kiyohara xs->status = SCSI_OK; 594 1.1 kiyohara xs->xs_status &= ~XS_STS_DONE; 595 1.1 kiyohara goto restart; 596 1.1 kiyohara } 597 1.1 kiyohara return error; 598 1.1 kiyohara } 599 1.1 kiyohara return 0; 600 1.1 kiyohara } 601 1.1 kiyohara 602 1.1 kiyohara static void 603 1.1 kiyohara siop_start(struct siop_adapter *adp, struct scsi_xfer *xs) 604 1.1 kiyohara { 605 1.1 kiyohara struct siop_xfer *siop_xfer = adp->xfer; 606 1.1 kiyohara uint32_t dsa, *script = adp->script; 607 1.2 mrg int slot; 608 1.1 kiyohara void *scriptaddr = (void *)local_to_PCI((u_long)script); 609 1.1 kiyohara const int siop_common_xfer_size = sizeof(struct siop_common_xfer); 610 1.1 kiyohara 611 1.1 kiyohara /* 612 1.1 kiyohara * The queue management here is a bit tricky: the script always looks 613 1.1 kiyohara * at the slot from first to last, so if we always use the first 614 1.1 kiyohara * free slot commands can stay at the tail of the queue ~forever. 615 1.1 kiyohara * The algorithm used here is to restart from the head when we know 616 1.1 kiyohara * that the queue is empty, and only add commands after the last one. 617 1.1 kiyohara * When we're at the end of the queue wait for the script to clear it. 618 1.1 kiyohara * The best thing to do here would be to implement a circular queue, 619 1.1 kiyohara * but using only 53c720 features this can be "interesting". 620 1.1 kiyohara * A mid-way solution could be to implement 2 queues and swap orders. 621 1.1 kiyohara */ 622 1.1 kiyohara slot = adp->currschedslot; 623 1.1 kiyohara /* 624 1.1 kiyohara * If the instruction is 0x80000000 (JUMP foo, IF FALSE) the slot is 625 1.1 kiyohara * free. As this is the last used slot, all previous slots are free, 626 1.1 kiyohara * we can restart from 0. 627 1.1 kiyohara */ 628 1.1 kiyohara if (ctoh32(script[(Ent_script_sched_slot0 / 4) + slot * 2]) == 629 1.1 kiyohara 0x80000000) { 630 1.1 kiyohara slot = adp->currschedslot = 0; 631 1.1 kiyohara } else { 632 1.1 kiyohara slot++; 633 1.1 kiyohara } 634 1.1 kiyohara /* 635 1.1 kiyohara * find a free scheduler slot and load it. 636 1.1 kiyohara */ 637 1.1 kiyohara #define SIOP_NSLOTS 0x40 638 1.1 kiyohara for (; slot < SIOP_NSLOTS; slot++) { 639 1.1 kiyohara /* 640 1.1 kiyohara * If cmd if 0x80000000 the slot is free 641 1.1 kiyohara */ 642 1.1 kiyohara if (ctoh32(script[(Ent_script_sched_slot0 / 4) + slot * 2]) == 643 1.1 kiyohara 0x80000000) 644 1.1 kiyohara break; 645 1.1 kiyohara } 646 1.1 kiyohara if (slot == SIOP_NSLOTS) { 647 1.1 kiyohara /* 648 1.1 kiyohara * no more free slot, no need to continue. freeze the queue 649 1.1 kiyohara * and requeue this command. 650 1.1 kiyohara */ 651 1.1 kiyohara printf("no mode free slot\n"); 652 1.1 kiyohara return; 653 1.1 kiyohara } 654 1.1 kiyohara 655 1.1 kiyohara /* patch scripts with DSA addr */ 656 1.1 kiyohara dsa = local_to_PCI((u_long)siop_xfer); 657 1.1 kiyohara 658 1.1 kiyohara /* CMD script: MOVE MEMORY addr */ 659 1.1 kiyohara siop_xfer->resel[E_ldsa_abs_slot_Used[0]] = 660 1.1 kiyohara htoc32(scriptaddr + Ent_script_sched_slot0 + slot * 8); 661 1.1 kiyohara _wbinv((u_long)siop_xfer, sizeof(*siop_xfer)); 662 1.1 kiyohara /* scheduler slot: JUMP ldsa_select */ 663 1.1 kiyohara script[(Ent_script_sched_slot0 / 4) + slot * 2 + 1] = 664 1.1 kiyohara htoc32(dsa + siop_common_xfer_size + Ent_ldsa_select); 665 1.1 kiyohara /* 666 1.1 kiyohara * Change JUMP cmd so that this slot will be handled 667 1.1 kiyohara */ 668 1.1 kiyohara script[(Ent_script_sched_slot0 / 4) + slot * 2] = htoc32(0x80080000); 669 1.1 kiyohara adp->currschedslot = slot; 670 1.1 kiyohara 671 1.1 kiyohara /* make sure SCRIPT processor will read valid data */ 672 1.1 kiyohara _wbinv((u_long)script, SIOP_SCRIPT_SIZE); 673 1.1 kiyohara /* Signal script it has some work to do */ 674 1.1 kiyohara writeb(adp->addr + SIOP_ISTAT, ISTAT_SIGP); 675 1.1 kiyohara /* and wait for IRQ */ 676 1.1 kiyohara } 677 1.1 kiyohara 678 1.1 kiyohara static void 679 1.1 kiyohara siop_xfer_setup(struct siop_xfer *xfer, void *scriptaddr) 680 1.1 kiyohara { 681 1.1 kiyohara const int off_msg_in = offsetof(struct siop_common_xfer, msg_in); 682 1.1 kiyohara const int off_status = offsetof(struct siop_common_xfer, status); 683 1.1 kiyohara uint32_t dsa, *scr; 684 1.1 kiyohara int i; 685 1.1 kiyohara 686 1.1 kiyohara memset(xfer, 0, sizeof(*xfer)); 687 1.1 kiyohara dsa = local_to_PCI((u_long)xfer); 688 1.1 kiyohara xfer->siop_tables.t_msgout.count = htoc32(1); 689 1.1 kiyohara xfer->siop_tables.t_msgout.addr = htoc32(dsa); 690 1.1 kiyohara xfer->siop_tables.t_msgin.count = htoc32(1); 691 1.1 kiyohara xfer->siop_tables.t_msgin.addr = htoc32(dsa + off_msg_in); 692 1.1 kiyohara xfer->siop_tables.t_extmsgin.count = htoc32(2); 693 1.1 kiyohara xfer->siop_tables.t_extmsgin.addr = htoc32(dsa + off_msg_in + 1); 694 1.1 kiyohara xfer->siop_tables.t_extmsgdata.addr = htoc32(dsa + off_msg_in + 3); 695 1.1 kiyohara xfer->siop_tables.t_status.count = htoc32(1); 696 1.1 kiyohara xfer->siop_tables.t_status.addr = htoc32(dsa + off_status); 697 1.1 kiyohara 698 1.1 kiyohara /* The select/reselect script */ 699 1.1 kiyohara scr = xfer->resel; 700 1.1 kiyohara for (i = 0; i < __arraycount(load_dsa); i++) 701 1.1 kiyohara scr[i] = htoc32(load_dsa[i]); 702 1.1 kiyohara 703 1.1 kiyohara /* 704 1.1 kiyohara * 0x78000000 is a 'move data8 to reg'. data8 is the second 705 1.1 kiyohara * octet, reg offset is the third. 706 1.1 kiyohara */ 707 1.1 kiyohara scr[Ent_rdsa0 / 4] = htoc32(0x78100000 | ((dsa & 0x000000ff) << 8)); 708 1.1 kiyohara scr[Ent_rdsa1 / 4] = htoc32(0x78110000 | ( dsa & 0x0000ff00 )); 709 1.1 kiyohara scr[Ent_rdsa2 / 4] = htoc32(0x78120000 | ((dsa & 0x00ff0000) >> 8)); 710 1.1 kiyohara scr[Ent_rdsa3 / 4] = htoc32(0x78130000 | ((dsa & 0xff000000) >> 16)); 711 1.1 kiyohara scr[E_ldsa_abs_reselected_Used[0]] = 712 1.1 kiyohara htoc32(scriptaddr + Ent_reselected); 713 1.1 kiyohara scr[E_ldsa_abs_reselect_Used[0]] = htoc32(scriptaddr + Ent_reselect); 714 1.1 kiyohara scr[E_ldsa_abs_selected_Used[0]] = htoc32(scriptaddr + Ent_selected); 715 1.1 kiyohara scr[E_ldsa_abs_data_Used[0]] = 716 1.1 kiyohara htoc32(dsa + sizeof(struct siop_common_xfer) + Ent_ldsa_data); 717 1.1 kiyohara /* JUMP foo, IF FALSE - used by MOVE MEMORY to clear the slot */ 718 1.1 kiyohara scr[Ent_ldsa_data / 4] = htoc32(0x80000000); 719 1.1 kiyohara } 720 1.1 kiyohara 721 1.1 kiyohara static int 722 1.1 kiyohara siop_add_reselsw(struct siop_adapter *adp, int target, int lunsw_off) 723 1.1 kiyohara { 724 1.1 kiyohara uint32_t *script = adp->script; 725 1.1 kiyohara int reseloff; 726 1.1 kiyohara void *scriptaddr = (void *)local_to_PCI((u_long)adp->script); 727 1.1 kiyohara 728 1.1 kiyohara /* 729 1.1 kiyohara * add an entry to resel switch 730 1.1 kiyohara */ 731 1.1 kiyohara reseloff = Ent_resel_targ0 / 4 + target * 2; 732 1.1 kiyohara if ((ctoh32(script[reseloff]) & 0xff) != 0xff) { 733 1.1 kiyohara /* it's not free */ 734 1.1 kiyohara printf("siop: resel switch full\n"); 735 1.1 kiyohara return EBUSY; 736 1.1 kiyohara } 737 1.1 kiyohara 738 1.1 kiyohara /* JUMP abs_foo, IF target | 0x80; */ 739 1.1 kiyohara script[reseloff + 0] = htoc32(0x800c0080 | target); 740 1.1 kiyohara script[reseloff + 1] = 741 1.1 kiyohara htoc32(scriptaddr + lunsw_off * 4 + Ent_lun_switch_entry); 742 1.1 kiyohara 743 1.1 kiyohara siop_update_scntl3(adp, target, lunsw_off); 744 1.1 kiyohara return 0; 745 1.1 kiyohara } 746 1.1 kiyohara 747 1.1 kiyohara static void 748 1.1 kiyohara siop_update_scntl3(struct siop_adapter *adp, int target, int lunsw_off) 749 1.1 kiyohara { 750 1.1 kiyohara uint32_t *script = adp->script; 751 1.1 kiyohara 752 1.1 kiyohara /* MOVE target->id >> 24 TO SCNTL3 */ 753 1.1 kiyohara script[lunsw_off + (Ent_restore_scntl3 / 4)] = 754 1.1 kiyohara htoc32(0x78030000 | ((adp->clock_div >> 16) & 0x0000ff00)); 755 1.1 kiyohara /* MOVE target->id >> 8 TO SXFER */ 756 1.1 kiyohara script[lunsw_off + (Ent_restore_scntl3 / 4) + 2] = 757 1.1 kiyohara htoc32(0x78050000 | (0x000000000 & 0x0000ff00)); 758 1.1 kiyohara _wbinv((u_long)script, SIOP_SCRIPT_SIZE); 759 1.1 kiyohara } 760 1.1 kiyohara 761 1.1 kiyohara 762 1.1 kiyohara /* 763 1.1 kiyohara * SCSI functions 764 1.1 kiyohara */ 765 1.1 kiyohara 766 1.1 kiyohara static int 767 1.9 rin _scsi_inquire(struct siop_adapter *adp, int t, int l, int buflen, void *buf) 768 1.1 kiyohara { 769 1.1 kiyohara struct scsipi_inquiry *cmd = (struct scsipi_inquiry *)adp->cmd; 770 1.1 kiyohara struct scsipi_inquiry_data *inqbuf = 771 1.1 kiyohara (struct scsipi_inquiry_data *)adp->data; 772 1.1 kiyohara struct scsi_xfer xs; 773 1.1 kiyohara int error; 774 1.1 kiyohara 775 1.1 kiyohara memset(cmd, 0, sizeof(*cmd)); 776 1.1 kiyohara cmd->opcode = INQUIRY; 777 1.1 kiyohara cmd->length = SCSIPI_INQUIRY_LENGTH_SCSI2; 778 1.1 kiyohara memset(inqbuf, 0, sizeof(*inqbuf)); 779 1.1 kiyohara 780 1.1 kiyohara memset(&xs, 0, sizeof(xs)); 781 1.1 kiyohara xs.target = t; 782 1.1 kiyohara xs.lun = l; 783 1.1 kiyohara xs.cmdlen = sizeof(*cmd); 784 1.1 kiyohara xs.cmd = (void *)cmd; 785 1.1 kiyohara xs.datalen = SCSIPI_INQUIRY_LENGTH_SCSI2; 786 1.1 kiyohara xs.data = (void *)inqbuf; 787 1.1 kiyohara 788 1.1 kiyohara xs.error = XS_NOERROR; 789 1.1 kiyohara xs.resid = xs.datalen; 790 1.1 kiyohara xs.status = SCSI_OK; 791 1.1 kiyohara 792 1.1 kiyohara error = siop_scsi_request(adp, &xs); 793 1.1 kiyohara if (error != 0) 794 1.1 kiyohara return error; 795 1.1 kiyohara 796 1.1 kiyohara memcpy(buf, inqbuf, buflen); 797 1.1 kiyohara return 0; 798 1.1 kiyohara } 799 1.1 kiyohara 800 1.1 kiyohara static void 801 1.1 kiyohara scsi_request_sense(struct siop_adapter *adp, struct scsi_xfer *xs) 802 1.1 kiyohara { 803 1.1 kiyohara struct scsi_request_sense *cmd = adp->sense; 804 1.1 kiyohara struct scsi_sense_data *data = (struct scsi_sense_data *)adp->data; 805 1.1 kiyohara struct scsi_xfer sense; 806 1.1 kiyohara int error; 807 1.1 kiyohara 808 1.1 kiyohara memset(cmd, 0, sizeof(struct scsi_request_sense)); 809 1.1 kiyohara cmd->opcode = SCSI_REQUEST_SENSE; 810 1.1 kiyohara cmd->length = sizeof(struct scsi_sense_data); 811 1.1 kiyohara memset(data, 0, sizeof(struct scsi_sense_data)); 812 1.1 kiyohara 813 1.1 kiyohara memset(&sense, 0, sizeof(sense)); 814 1.1 kiyohara sense.target = xs->target; 815 1.1 kiyohara sense.lun = xs->lun; 816 1.1 kiyohara sense.cmdlen = sizeof(struct scsi_request_sense); 817 1.1 kiyohara sense.cmd = (void *)cmd; 818 1.1 kiyohara sense.datalen = sizeof(struct scsi_sense_data); 819 1.1 kiyohara sense.data = (void *)data; 820 1.1 kiyohara 821 1.1 kiyohara sense.error = XS_NOERROR; 822 1.1 kiyohara sense.resid = sense.datalen; 823 1.1 kiyohara sense.status = SCSI_OK; 824 1.1 kiyohara 825 1.1 kiyohara error = siop_scsi_request(adp, &sense); 826 1.1 kiyohara switch (error) { 827 1.1 kiyohara case 0: 828 1.1 kiyohara /* we have a valid sense */ 829 1.1 kiyohara xs->error = XS_SENSE; 830 1.1 kiyohara return; 831 1.1 kiyohara case EINTR: 832 1.1 kiyohara /* REQUEST_SENSE interrupted by bus reset. */ 833 1.1 kiyohara xs->error = XS_RESET; 834 1.1 kiyohara return; 835 1.1 kiyohara case EIO: 836 1.4 andvar /* request sense couldn't be performed */ 837 1.1 kiyohara /* 838 1.1 kiyohara * XXX this isn't quite right but we don't have anything 839 1.1 kiyohara * better for now 840 1.1 kiyohara */ 841 1.1 kiyohara xs->error = XS_DRIVER_STUFFUP; 842 1.1 kiyohara return; 843 1.1 kiyohara default: 844 1.1 kiyohara /* Notify that request sense failed. */ 845 1.1 kiyohara xs->error = XS_DRIVER_STUFFUP; 846 1.1 kiyohara printf("request sense failed with error %d\n", error); 847 1.1 kiyohara return; 848 1.1 kiyohara } 849 1.1 kiyohara } 850 1.1 kiyohara 851 1.1 kiyohara /* 852 1.1 kiyohara * scsi_interpret_sense: 853 1.1 kiyohara * 854 1.1 kiyohara * Look at the returned sense and act on the error, determining 855 1.1 kiyohara * the unix error number to pass back. (0 = report no error) 856 1.1 kiyohara * 857 1.4 andvar * NOTE: If we return ERESTART, we are expected to have 858 1.1 kiyohara * thawed the device! 859 1.1 kiyohara * 860 1.1 kiyohara * THIS IS THE DEFAULT ERROR HANDLER FOR SCSI DEVICES. 861 1.1 kiyohara */ 862 1.1 kiyohara static int 863 1.1 kiyohara scsi_interpret_sense(struct siop_adapter *adp, struct scsi_xfer *xs) 864 1.1 kiyohara { 865 1.1 kiyohara struct scsi_sense_data *sense; 866 1.1 kiyohara u_int8_t key; 867 1.3 skrll int error = 0; 868 1.1 kiyohara uint32_t info; 869 1.1 kiyohara static const char *error_mes[] = { 870 1.1 kiyohara "soft error (corrected)", 871 1.1 kiyohara "not ready", "medium error", 872 1.1 kiyohara "non-media hardware failure", "illegal request", 873 1.1 kiyohara "unit attention", "readonly device", 874 1.1 kiyohara "no data found", "vendor unique", 875 1.1 kiyohara "copy aborted", "command aborted", 876 1.1 kiyohara "search returned equal", "volume overflow", 877 1.1 kiyohara "verify miscompare", "unknown error key" 878 1.1 kiyohara }; 879 1.1 kiyohara 880 1.1 kiyohara sense = (struct scsi_sense_data *)xs->data; 881 1.1 kiyohara 882 1.1 kiyohara /* otherwise use the default */ 883 1.1 kiyohara switch (SSD_RCODE(sense->response_code)) { 884 1.1 kiyohara 885 1.1 kiyohara /* 886 1.1 kiyohara * Old SCSI-1 and SASI devices respond with 887 1.1 kiyohara * codes other than 70. 888 1.1 kiyohara */ 889 1.1 kiyohara case 0x00: /* no error (command completed OK) */ 890 1.1 kiyohara return 0; 891 1.1 kiyohara case 0x04: /* drive not ready after it was selected */ 892 1.1 kiyohara if (adp->sd->sc_flags & FLAGS_REMOVABLE) 893 1.1 kiyohara adp->sd->sc_flags &= ~FLAGS_MEDIA_LOADED; 894 1.1 kiyohara /* XXX - display some sort of error here? */ 895 1.1 kiyohara return EIO; 896 1.1 kiyohara case 0x20: /* invalid command */ 897 1.1 kiyohara return EINVAL; 898 1.1 kiyohara case 0x25: /* invalid LUN (Adaptec ACB-4000) */ 899 1.1 kiyohara return EACCES; 900 1.1 kiyohara 901 1.1 kiyohara /* 902 1.1 kiyohara * If it's code 70, use the extended stuff and 903 1.1 kiyohara * interpret the key 904 1.1 kiyohara */ 905 1.1 kiyohara case 0x71: /* delayed error */ 906 1.1 kiyohara key = SSD_SENSE_KEY(sense->flags); 907 1.1 kiyohara printf(" DEFERRED ERROR, key = 0x%x\n", key); 908 1.1 kiyohara /* FALLTHROUGH */ 909 1.1 kiyohara case 0x70: 910 1.1 kiyohara if ((sense->response_code & SSD_RCODE_VALID) != 0) 911 1.1 kiyohara info = _4btol(sense->info); 912 1.1 kiyohara else 913 1.1 kiyohara info = 0; 914 1.1 kiyohara key = SSD_SENSE_KEY(sense->flags); 915 1.1 kiyohara 916 1.1 kiyohara switch (key) { 917 1.1 kiyohara case SKEY_NO_SENSE: 918 1.1 kiyohara case SKEY_RECOVERED_ERROR: 919 1.1 kiyohara if (xs->resid == xs->datalen && xs->datalen) { 920 1.1 kiyohara /* 921 1.1 kiyohara * Why is this here? 922 1.1 kiyohara */ 923 1.1 kiyohara xs->resid = 0; /* not short read */ 924 1.1 kiyohara } 925 1.1 kiyohara case SKEY_EQUAL: 926 1.1 kiyohara break; 927 1.1 kiyohara case SKEY_NOT_READY: 928 1.1 kiyohara if (adp->sd->sc_flags & FLAGS_REMOVABLE) 929 1.1 kiyohara adp->sd->sc_flags &= ~FLAGS_MEDIA_LOADED; 930 1.1 kiyohara if (sense->asc == 0x3A) { 931 1.1 kiyohara error = ENODEV; /* Medium not present */ 932 1.1 kiyohara } else 933 1.1 kiyohara error = EIO; 934 1.1 kiyohara break; 935 1.1 kiyohara case SKEY_ILLEGAL_REQUEST: 936 1.1 kiyohara error = EINVAL; 937 1.1 kiyohara break; 938 1.1 kiyohara case SKEY_UNIT_ATTENTION: 939 1.1 kiyohara if (sense->asc == 0x29 && 940 1.1 kiyohara sense->ascq == 0x00) { 941 1.1 kiyohara /* device or bus reset */ 942 1.1 kiyohara return ERESTART; 943 1.1 kiyohara } 944 1.1 kiyohara if (adp->sd->sc_flags & FLAGS_REMOVABLE) 945 1.1 kiyohara adp->sd->sc_flags &= ~FLAGS_MEDIA_LOADED; 946 1.1 kiyohara if (!(adp->sd->sc_flags & FLAGS_REMOVABLE)) 947 1.1 kiyohara return ERESTART; 948 1.1 kiyohara error = EIO; 949 1.1 kiyohara break; 950 1.1 kiyohara case SKEY_DATA_PROTECT: 951 1.1 kiyohara error = EROFS; 952 1.1 kiyohara break; 953 1.1 kiyohara case SKEY_BLANK_CHECK: 954 1.1 kiyohara break; 955 1.1 kiyohara case SKEY_ABORTED_COMMAND: 956 1.1 kiyohara break; 957 1.1 kiyohara case SKEY_VOLUME_OVERFLOW: 958 1.1 kiyohara error = ENOSPC; 959 1.1 kiyohara break; 960 1.1 kiyohara default: 961 1.1 kiyohara error = EIO; 962 1.1 kiyohara break; 963 1.1 kiyohara } 964 1.1 kiyohara 965 1.1 kiyohara /* Print brief(er) sense information */ 966 1.1 kiyohara printf("%s", error_mes[key - 1]); 967 1.1 kiyohara if ((sense->response_code & SSD_RCODE_VALID) != 0) { 968 1.1 kiyohara switch (key) { 969 1.1 kiyohara case SKEY_NOT_READY: 970 1.1 kiyohara case SKEY_ILLEGAL_REQUEST: 971 1.1 kiyohara case SKEY_UNIT_ATTENTION: 972 1.1 kiyohara case SKEY_DATA_PROTECT: 973 1.1 kiyohara break; 974 1.1 kiyohara case SKEY_BLANK_CHECK: 975 1.1 kiyohara printf(", requested size: %d (decimal)", 976 1.1 kiyohara info); 977 1.1 kiyohara break; 978 1.1 kiyohara case SKEY_ABORTED_COMMAND: 979 1.1 kiyohara printf(", cmd 0x%x, info 0x%x", 980 1.1 kiyohara xs->cmd->opcode, info); 981 1.1 kiyohara break; 982 1.1 kiyohara default: 983 1.1 kiyohara printf(", info = %d (decimal)", info); 984 1.1 kiyohara } 985 1.1 kiyohara } 986 1.1 kiyohara if (sense->extra_len != 0) { 987 1.1 kiyohara int n; 988 1.1 kiyohara printf(", data ="); 989 1.1 kiyohara for (n = 0; n < sense->extra_len; n++) 990 1.1 kiyohara printf(" %x", sense->csi[n]); 991 1.1 kiyohara } 992 1.1 kiyohara printf("\n"); 993 1.1 kiyohara return error; 994 1.1 kiyohara 995 1.1 kiyohara /* 996 1.1 kiyohara * Some other code, just report it 997 1.1 kiyohara */ 998 1.1 kiyohara default: 999 1.1 kiyohara printf("Sense Error Code 0x%x", 1000 1.1 kiyohara SSD_RCODE(sense->response_code)); 1001 1.1 kiyohara if ((sense->response_code & SSD_RCODE_VALID) != 0) { 1002 1.1 kiyohara struct scsi_sense_data_unextended *usense = 1003 1.1 kiyohara (struct scsi_sense_data_unextended *)sense; 1004 1.1 kiyohara printf(" at block no. %d (decimal)", 1005 1.1 kiyohara _3btol(usense->block)); 1006 1.1 kiyohara } 1007 1.1 kiyohara printf("\n"); 1008 1.1 kiyohara return EIO; 1009 1.1 kiyohara } 1010 1.1 kiyohara } 1011 1.1 kiyohara 1012 1.1 kiyohara static int 1013 1.1 kiyohara scsi_probe(struct siop_adapter *adp) 1014 1.1 kiyohara { 1015 1.9 rin struct scsipi_inquiry_data buf, *inqbuf = &buf; 1016 1.1 kiyohara int found, t, l; 1017 1.1 kiyohara uint8_t device; 1018 1.9 rin char product[sizeof(inqbuf->product) + 1]; 1019 1.1 kiyohara 1020 1.10 rin memset(&buf, 0, sizeof(buf)); 1021 1.10 rin 1022 1.1 kiyohara found = 0; 1023 1.1 kiyohara for (t = 0; t < 8; t++) { 1024 1.1 kiyohara if (t == adp->id) 1025 1.1 kiyohara continue; 1026 1.1 kiyohara for (l = 0; l < 8; l++) { 1027 1.9 rin if (_scsi_inquire(adp, t, l, 1028 1.10 rin SCSIPI_INQUIRY_LENGTH_SCSI2, &buf) != 0) 1029 1.1 kiyohara continue; 1030 1.1 kiyohara 1031 1.1 kiyohara device = inqbuf->device & SID_TYPE; 1032 1.1 kiyohara if (device == T_NODEVICE) 1033 1.1 kiyohara continue; 1034 1.1 kiyohara if (device != T_DIRECT && 1035 1.1 kiyohara device != T_OPTICAL && 1036 1.1 kiyohara device != T_SIMPLE_DIRECT) 1037 1.1 kiyohara continue; 1038 1.1 kiyohara 1039 1.1 kiyohara memset(product, 0, sizeof(product)); 1040 1.1 kiyohara strncpy(product, inqbuf->product, sizeof(product) - 1); 1041 1.1 kiyohara printf("sd(%d,%d,[0-7]): <%s>\n", t, l, product); 1042 1.1 kiyohara found++; 1043 1.1 kiyohara } 1044 1.1 kiyohara } 1045 1.1 kiyohara return found; 1046 1.1 kiyohara } 1047 1.1 kiyohara 1048 1.1 kiyohara int 1049 1.1 kiyohara scsi_inquire(struct sd_softc *sd, int buflen, void *buf) 1050 1.1 kiyohara { 1051 1.1 kiyohara struct siop_adapter *adp; 1052 1.1 kiyohara int error; 1053 1.1 kiyohara 1054 1.1 kiyohara if (sd->sc_bus != 0) 1055 1.1 kiyohara return ENOTSUP; 1056 1.1 kiyohara if (adapt.addr == 0xffffffff) 1057 1.1 kiyohara return ENOENT; 1058 1.1 kiyohara adp = &adapt; 1059 1.1 kiyohara 1060 1.1 kiyohara adp->sd = sd; 1061 1.1 kiyohara error = _scsi_inquire(adp, sd->sc_target, sd->sc_lun, buflen, buf); 1062 1.1 kiyohara adp->sd = NULL; 1063 1.1 kiyohara 1064 1.1 kiyohara return error; 1065 1.1 kiyohara } 1066 1.1 kiyohara 1067 1.1 kiyohara /* 1068 1.1 kiyohara * scsi_mode_sense 1069 1.1 kiyohara * get a sense page from a device 1070 1.1 kiyohara */ 1071 1.1 kiyohara 1072 1.1 kiyohara int 1073 1.1 kiyohara scsi_mode_sense(struct sd_softc *sd, int byte2, int page, 1074 1.1 kiyohara struct scsi_mode_parameter_header_6 *data, int len) 1075 1.1 kiyohara { 1076 1.1 kiyohara struct scsi_mode_sense_6 cmd; 1077 1.1 kiyohara 1078 1.1 kiyohara memset(&cmd, 0, sizeof(cmd)); 1079 1.1 kiyohara cmd.opcode = SCSI_MODE_SENSE_6; 1080 1.1 kiyohara cmd.byte2 = byte2; 1081 1.1 kiyohara cmd.page = page; 1082 1.1 kiyohara cmd.length = len & 0xff; 1083 1.1 kiyohara 1084 1.1 kiyohara return scsi_command(sd, (void *)&cmd, sizeof(cmd), (void *)data, len); 1085 1.1 kiyohara } 1086 1.1 kiyohara 1087 1.1 kiyohara int 1088 1.1 kiyohara scsi_command(struct sd_softc *sd, void *cmd, int cmdlen, void *data, 1089 1.1 kiyohara int datalen) 1090 1.1 kiyohara { 1091 1.1 kiyohara struct siop_adapter *adp; 1092 1.1 kiyohara struct scsi_xfer xs; 1093 1.1 kiyohara int error; 1094 1.1 kiyohara 1095 1.1 kiyohara if (sd->sc_bus != 0) 1096 1.1 kiyohara return ENOTSUP; 1097 1.1 kiyohara if (adapt.addr == 0xffffffff) 1098 1.1 kiyohara return ENOENT; 1099 1.1 kiyohara adp = &adapt; 1100 1.1 kiyohara 1101 1.1 kiyohara memcpy(adp->cmd, cmd, cmdlen); 1102 1.1 kiyohara adp->sd = sd; 1103 1.1 kiyohara 1104 1.1 kiyohara memset(&xs, 0, sizeof(xs)); 1105 1.1 kiyohara xs.target = sd->sc_target; 1106 1.1 kiyohara xs.lun = sd->sc_lun; 1107 1.1 kiyohara xs.cmdlen = cmdlen; 1108 1.1 kiyohara xs.cmd = adp->cmd; 1109 1.1 kiyohara xs.datalen = datalen; 1110 1.1 kiyohara xs.data = adp->data; 1111 1.1 kiyohara 1112 1.1 kiyohara xs.error = XS_NOERROR; 1113 1.1 kiyohara xs.resid = datalen; 1114 1.1 kiyohara xs.status = SCSI_OK; 1115 1.1 kiyohara 1116 1.1 kiyohara error = siop_scsi_request(adp, &xs); 1117 1.1 kiyohara adp->sd = NULL; 1118 1.1 kiyohara if (error != 0) 1119 1.1 kiyohara return error; 1120 1.1 kiyohara 1121 1.1 kiyohara if (datalen > 0) 1122 1.1 kiyohara memcpy(data, adp->data, datalen); 1123 1.1 kiyohara return 0; 1124 1.1 kiyohara } 1125 1.1 kiyohara 1126 1.1 kiyohara /* 1127 1.1 kiyohara * Initialize the device. 1128 1.1 kiyohara */ 1129 1.1 kiyohara int 1130 1.1 kiyohara siop_init(int bus, int dev, int func) 1131 1.1 kiyohara { 1132 1.1 kiyohara struct siop_adapter tmp; 1133 1.1 kiyohara struct siop_xfer *xfer; 1134 1.1 kiyohara struct scsipi_generic *cmd; 1135 1.1 kiyohara struct scsi_request_sense *sense; 1136 1.1 kiyohara uint32_t reg; 1137 1.1 kiyohara u_long addr; 1138 1.1 kiyohara uint32_t *script; 1139 1.1 kiyohara int slot, id, i; 1140 1.1 kiyohara void *scriptaddr; 1141 1.1 kiyohara u_char *data; 1142 1.1 kiyohara const int clock_div = 3; /* 53c810 */ 1143 1.1 kiyohara 1144 1.1 kiyohara slot = PCISlotnum(bus, dev, func); 1145 1.1 kiyohara if (slot == -1) 1146 1.1 kiyohara return ENOENT; 1147 1.1 kiyohara 1148 1.1 kiyohara addr = PCIAddress(slot, 1, PCI_MAPREG_TYPE_MEM); 1149 1.1 kiyohara if (addr == 0xffffffff) 1150 1.1 kiyohara return EINVAL; 1151 1.1 kiyohara enablePCI(slot, 0, 1, 1); 1152 1.1 kiyohara 1153 1.1 kiyohara script = ALLOC(uint32_t, SIOP_SCRIPT_SIZE); 1154 1.1 kiyohara if (script == NULL) 1155 1.1 kiyohara return ENOMEM; 1156 1.1 kiyohara scriptaddr = (void *)local_to_PCI((u_long)script); 1157 1.1 kiyohara cmd = ALLOC(struct scsipi_generic, SIOP_SCSI_COMMAND_SIZE); 1158 1.1 kiyohara if (cmd == NULL) 1159 1.1 kiyohara return ENOMEM; 1160 1.1 kiyohara sense = ALLOC(struct scsi_request_sense, SIOP_SCSI_COMMAND_SIZE); 1161 1.1 kiyohara if (sense == NULL) 1162 1.1 kiyohara return ENOMEM; 1163 1.1 kiyohara data = ALLOC(u_char, SIOP_SCSI_DATA_SIZE); 1164 1.1 kiyohara if (data == NULL) 1165 1.1 kiyohara return ENOMEM; 1166 1.1 kiyohara xfer = ALLOC(struct siop_xfer, sizeof(struct siop_xfer)); 1167 1.1 kiyohara if (xfer == NULL) 1168 1.1 kiyohara return ENOMEM; 1169 1.1 kiyohara siop_xfer_setup(xfer, scriptaddr); 1170 1.1 kiyohara 1171 1.1 kiyohara id = readb(addr + SIOP_SCID) & SCID_ENCID_MASK; 1172 1.1 kiyohara 1173 1.1 kiyohara /* reset bus */ 1174 1.1 kiyohara reg = readb(addr + SIOP_SCNTL1); 1175 1.1 kiyohara writeb(addr + SIOP_SCNTL1, reg | SCNTL1_RST); 1176 1.1 kiyohara delay(100); 1177 1.1 kiyohara writeb(addr + SIOP_SCNTL1, reg); 1178 1.1 kiyohara 1179 1.1 kiyohara /* reset the chip */ 1180 1.1 kiyohara writeb(addr + SIOP_ISTAT, ISTAT_SRST); 1181 1.1 kiyohara delay(1000); 1182 1.1 kiyohara writeb(addr + SIOP_ISTAT, 0); 1183 1.1 kiyohara 1184 1.1 kiyohara /* init registers */ 1185 1.1 kiyohara writeb(addr + SIOP_SCNTL0, SCNTL0_ARB_MASK | SCNTL0_EPC | SCNTL0_AAP); 1186 1.1 kiyohara writeb(addr + SIOP_SCNTL1, 0); 1187 1.1 kiyohara writeb(addr + SIOP_SCNTL3, clock_div); 1188 1.1 kiyohara writeb(addr + SIOP_SXFER, 0); 1189 1.1 kiyohara writeb(addr + SIOP_DIEN, 0xff); 1190 1.1 kiyohara writeb(addr + SIOP_SIEN0, 0xff & ~(SIEN0_CMP | SIEN0_SEL | SIEN0_RSL)); 1191 1.1 kiyohara writeb(addr + SIOP_SIEN1, 0xff & ~(SIEN1_HTH | SIEN1_GEN)); 1192 1.1 kiyohara writeb(addr + SIOP_STEST2, 0); 1193 1.1 kiyohara writeb(addr + SIOP_STEST3, STEST3_TE); 1194 1.1 kiyohara writeb(addr + SIOP_STIME0, (0xb << STIME0_SEL_SHIFT)); 1195 1.1 kiyohara writeb(addr + SIOP_SCID, id | SCID_RRE); 1196 1.1 kiyohara writeb(addr + SIOP_RESPID0, 1 << id); 1197 1.1 kiyohara writeb(addr + SIOP_DCNTL, DCNTL_COM); 1198 1.1 kiyohara 1199 1.1 kiyohara siop_pci_reset(addr); 1200 1.1 kiyohara 1201 1.1 kiyohara /* copy and patch the script */ 1202 1.1 kiyohara for (i = 0; i < __arraycount(siop_script); i++) 1203 1.1 kiyohara script[i] = htoc32(siop_script[i]); 1204 1.1 kiyohara for (i = 0; i < __arraycount(E_abs_msgin_Used); i++) 1205 1.1 kiyohara script[E_abs_msgin_Used[i]] = 1206 1.1 kiyohara htoc32(scriptaddr + Ent_msgin_space); 1207 1.1 kiyohara 1208 1.1 kiyohara /* start script */ 1209 1.1 kiyohara _wbinv((u_long)script, SIOP_SCRIPT_SIZE); 1210 1.1 kiyohara writel(addr + SIOP_DSP, (int)scriptaddr + Ent_reselect); 1211 1.1 kiyohara 1212 1.1 kiyohara memset(&tmp, 0, sizeof(tmp)); 1213 1.1 kiyohara tmp.id = id; 1214 1.1 kiyohara tmp.clock_div = clock_div; 1215 1.1 kiyohara tmp.addr = addr; 1216 1.1 kiyohara tmp.script = script; 1217 1.1 kiyohara tmp.xfer = xfer; 1218 1.1 kiyohara tmp.cmd = cmd; 1219 1.1 kiyohara tmp.sense = sense; 1220 1.1 kiyohara tmp.data = data; 1221 1.1 kiyohara tmp.currschedslot = 0; 1222 1.1 kiyohara tmp.sel_t = -1; 1223 1.1 kiyohara 1224 1.1 kiyohara if (scsi_probe(&tmp) == 0) { 1225 1.1 kiyohara adapt.addr = 0xffffffff; 1226 1.1 kiyohara return ENXIO; 1227 1.1 kiyohara } 1228 1.1 kiyohara adapt = tmp; 1229 1.1 kiyohara return 0; 1230 1.1 kiyohara } 1231