11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of PCI-SCSI IO processors. 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 1999-2001 Gerard Roudier <groudier@free.fr> 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (c) 2003-2005 Matthew Wilcox <matthew@wil.cx> 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This driver is derived from the Linux sym53c8xx driver. 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 1998-2000 Gerard Roudier 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The sym53c8xx driver is derived from the ncr53c8xx driver that had been 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a port of the FreeBSD ncr driver to Linux-1.2.13. 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The original ncr driver has been written for 386bsd and FreeBSD by 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wolfgang Stanglmeier <wolf@cologne.de> 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Stefan Esser <se@mi.Uni-Koeln.de> 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 1994 Wolfgang Stanglmeier 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Other major contributions: 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * NVRAM detection and reading. 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk> 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *----------------------------------------------------------------------------- 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2 of the License, or 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (at your option) any later version. 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful, 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * GNU General Public License for more details. 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * along with this program; if not, write to the Free Software 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 404e57b6817880946a3a78d5d8cad1ace363f7e449Tim Schmielau 414e57b6817880946a3a78d5d8cad1ace363f7e449Tim Schmielau#include <linux/slab.h> 428c65b4a60450590e79a28e9717ceffa9e4debb3fTim Schmielau#include <asm/param.h> /* for timeouts in units of HZ */ 434e57b6817880946a3a78d5d8cad1ace363f7e449Tim Schmielau 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "sym_glue.h" 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "sym_nvram.h" 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define SYM_DEBUG_GENERIC_SUPPORT 491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Needed function prototypes. 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sym_int_ma (struct sym_hcb *np); 553fb364e089e05c35ead55a08d56d3004193681f6Matthew Wilcoxstatic void sym_int_sir(struct sym_hcb *); 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sym_ccb *sym_alloc_ccb(struct sym_hcb *np); 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sym_ccb *sym_ccb_from_dsa(struct sym_hcb *np, u32 dsa); 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sym_alloc_lcb_tags (struct sym_hcb *np, u_char tn, u_char ln); 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sym_complete_error (struct sym_hcb *np, struct sym_ccb *cp); 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sym_complete_ok (struct sym_hcb *np, struct sym_ccb *cp); 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int sym_compute_residual(struct sym_hcb *np, struct sym_ccb *cp); 621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Print a buffer in hexadecimal format with a ".\n" at end. 651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sym_printl_hex(u_char *p, int n) 671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (n-- > 0) 691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf (" %x", *p++); 701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf (".\n"); 711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sym_print_msg(struct sym_ccb *cp, char *label, u_char *msg) 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 752e4c332913b5d39fef686b3964098f0d8fd97eadDavid Miller sym_print_addr(cp->cmd, "%s: ", label); 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 771abfd370134553f3b47e3e40a0526e05001409c2Matthew Wilcox spi_print_msg(msg); 7833333bacf523bb4bb903058fec6041a5952c93c6Matthew Wilcox printf("\n"); 791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sym_print_nego_msg(struct sym_hcb *np, int target, char *label, u_char *msg) 821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_tcb *tp = &np->target[target]; 8453222b906903fd861dc24ebccfa07ee125941313Matthew Wilcox dev_info(&tp->starget->dev, "%s: ", label); 851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 861abfd370134553f3b47e3e40a0526e05001409c2Matthew Wilcox spi_print_msg(msg); 8733333bacf523bb4bb903058fec6041a5952c93c6Matthew Wilcox printf("\n"); 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Print something that tells about extended errors. 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid sym_print_xerr(struct scsi_cmnd *cmd, int x_status) 941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (x_status & XE_PARITY_ERR) { 961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_print_addr(cmd, "unrecovered SCSI parity error.\n"); 971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (x_status & XE_EXTRA_DATA) { 991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_print_addr(cmd, "extraneous data discarded.\n"); 1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (x_status & XE_BAD_PHASE) { 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_print_addr(cmd, "illegal scsi phase (4/5).\n"); 1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (x_status & XE_SODL_UNRUN) { 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_print_addr(cmd, "ODD transfer in DATA OUT phase.\n"); 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (x_status & XE_SWIDE_OVRUN) { 1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_print_addr(cmd, "ODD transfer in DATA IN phase.\n"); 1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Return a string for SCSI BUS mode. 1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char *sym_scsi_bus_mode(int mode) 1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch(mode) { 1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SMODE_HVD: return "HVD"; 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SMODE_SE: return "SE"; 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SMODE_LVD: return "LVD"; 1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return "??"; 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Soft reset the chip. 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Raising SRST when the chip is running may cause 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * problems on dual function chips (see below). 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * On the other hand, LVD devices need some delay 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to settle and report actual BUS mode in STEST4. 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sym_chip_reset (struct sym_hcb *np) 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_istat, SRST); 13653222b906903fd861dc24ebccfa07ee125941313Matthew Wilcox INB(np, nc_mbox1); 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(10); 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_istat, 0); 13953222b906903fd861dc24ebccfa07ee125941313Matthew Wilcox INB(np, nc_mbox1); 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(2000); /* For BUS MODE to settle */ 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Really soft reset the chip.:) 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Some 896 and 876 chip revisions may hang-up if we set 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the SRST (soft reset) bit at the wrong time when SCRIPTS 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * are running. 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * So, we need to abort the current operation prior to 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * soft resetting the chip. 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sym_soft_reset (struct sym_hcb *np) 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char istat = 0; 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(np->features & FE_ISTAT1) || !(INB(np, nc_istat1) & SCRUN)) 1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto do_chip_reset; 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_istat, CABRT); 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 100000 ; i ; --i) { 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds istat = INB(np, nc_istat); 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (istat & SIP) { 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INW(np, nc_sist); 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (istat & DIP) { 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (INB(np, nc_dstat) & ABRT) 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(5); 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_istat, 0); 1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!i) 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf("%s: unable to abort current chip operation, " 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "ISTAT=0x%02x.\n", sym_name(np), istat); 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsdo_chip_reset: 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_chip_reset(np); 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Start reset process. 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The interrupt handler will reinitialize the chip. 1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sym_start_reset(struct sym_hcb *np) 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_reset_scsi_bus(np, 1); 1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint sym_reset_scsi_bus(struct sym_hcb *np, int enab_int) 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 term; 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int retv = 0; 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_soft_reset(np); /* Soft reset the chip */ 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (enab_int) 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTW(np, nc_sien, RST); 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Enable Tolerant, reset IRQD if present and 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * properly set IRQ mode, prior to resetting the bus. 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_stest3, TE); 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_dcntl, (np->rv_dcntl & IRQM)); 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_scntl1, CRST); 20553222b906903fd861dc24ebccfa07ee125941313Matthew Wilcox INB(np, nc_mbox1); 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(200); 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!SYM_SETUP_SCSI_BUS_CHECK) 2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Check for no terminators or SCSI bus shorts to ground. 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Read SCSI data bus, data parity bits and control signals. 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We are expecting RESET to be TRUE and other signals to be 2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * FALSE. 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds term = INB(np, nc_sstat0); 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds term = ((term & 2) << 7) + ((term & 1) << 17); /* rst sdp0 */ 2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds term |= ((INB(np, nc_sstat2) & 0x01) << 26) | /* sdp1 */ 2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((INW(np, nc_sbdl) & 0xff) << 9) | /* d7-0 */ 2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ((INW(np, nc_sbdl) & 0xff00) << 10) | /* d15-8 */ 2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INB(np, nc_sbcl); /* req ack bsy sel atn msg cd io */ 2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!np->maxwide) 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds term &= 0x3ffff; 2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (term != (2<<7)) { 2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf("%s: suspicious SCSI data while resetting the BUS.\n", 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_name(np)); 2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf("%s: %sdp0,d7-0,rst,req,ack,bsy,sel,atn,msg,c/d,i/o = " 2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "0x%lx, expecting 0x%lx\n", 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_name(np), 2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (np->features & FE_WIDE) ? "dp1,d15-8," : "", 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (u_long)term, (u_long)(2<<7)); 2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (SYM_SETUP_SCSI_BUS_CHECK == 1) 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds retv = 1; 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_scntl1, 0); 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return retv; 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Select SCSI clock frequency 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sym_selectclock(struct sym_hcb *np, u_char scntl3) 2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If multiplier not present or not selected, leave here. 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->multiplier <= 1) { 2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_scntl3, scntl3); 2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sym_verbose >= 2) 2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf ("%s: enabling clock multiplier\n", sym_name(np)); 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_stest1, DBLEN); /* Enable clock multiplier */ 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wait for the LCKFRQ bit to be set if supported by the chip. 2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Otherwise wait 50 micro-seconds (at least). 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->features & FE_LCKFRQ) { 2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i = 20; 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (!(INB(np, nc_stest4) & LCKFRQ) && --i > 0) 2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(20); 2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!i) 2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf("%s: the chip cannot lock the frequency\n", 2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_name(np)); 27053222b906903fd861dc24ebccfa07ee125941313Matthew Wilcox } else { 27153222b906903fd861dc24ebccfa07ee125941313Matthew Wilcox INB(np, nc_mbox1); 27253222b906903fd861dc24ebccfa07ee125941313Matthew Wilcox udelay(50+10); 27353222b906903fd861dc24ebccfa07ee125941313Matthew Wilcox } 2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_stest3, HSC); /* Halt the scsi clock */ 2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_scntl3, scntl3); 2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_stest1, (DBLEN|DBLSEL));/* Select clock multiplier */ 2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_stest3, 0x00); /* Restart scsi clock */ 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Determine the chip's clock frequency. 2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is essential for the negotiation of the synchronous 2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * transfer rate. 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note: we have to return the correct value. 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * THERE IS NO SAFE DEFAULT VALUE. 2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Most NCR/SYMBIOS boards are delivered with a 40 Mhz clock. 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 53C860 and 53C875 rev. 1 support fast20 transfers but 2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * do not have a clock doubler and so are provided with a 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 80 MHz clock. All other fast20 boards incorporate a doubler 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and so should be delivered with a 40 MHz clock. 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The recent fast40 chips (895/896/895A/1010) use a 40 Mhz base 2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * clock and provide a clock quadrupler (160 Mhz). 2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * calculate SCSI clock frequency (in KHz) 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned getfreq (struct sym_hcb *np, int gen) 3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int ms = 0; 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int f; 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Measure GEN timer delay in order 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to calculate SCSI clock frequency 3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This code will never execute too 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * many loop iterations (if DELAY is 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * reasonably correct). It could get 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * too low a delay (too high a freq.) 3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if the CPU is slow executing the 3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * loop for some reason (an NMI, for 3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * example). For this reason we will 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if multiple measurements are to be 3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * performed trust the higher delay 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (lower frequency returned). 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTW(np, nc_sien, 0); /* mask all scsi interrupts */ 3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INW(np, nc_sist); /* clear pending scsi interrupt */ 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_dien, 0); /* mask all dma interrupts */ 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INW(np, nc_sist); /* another one, just to be sure :) */ 3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The C1010-33 core does not report GEN in SIST, 3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if this interrupt is masked in SIEN. 3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * I don't know yet if the C1010-66 behaves the same way. 3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->features & FE_C10) { 3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTW(np, nc_sien, GEN); 3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_istat1, SIRQD); 3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_scntl3, 4); /* set pre-scaler to divide by 3 */ 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_stime1, 0); /* disable general purpose timer */ 3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_stime1, gen); /* set to nominal delay of 1<<gen * 125us */ 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (!(INW(np, nc_sist) & GEN) && ms++ < 100000) 3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(1000/4); /* count in 1/4 of ms */ 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_stime1, 0); /* disable general purpose timer */ 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Undo C1010-33 specific settings. 3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->features & FE_C10) { 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTW(np, nc_sien, 0); 3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_istat1, 0); 3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * set prescaler to divide by whatever 0 means 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0 ought to choose divide by 2, but appears 3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to set divide by 3.5 mode in my 53c810 ... 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_scntl3, 0); 3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * adjust for prescaler, and convert into KHz 3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds f = ms ? ((1 << gen) * (4340*4)) / ms : 0; 3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The C1010-33 result is biased by a factor 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of 2/3 compared to earlier chips. 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->features & FE_C10) 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds f = (f * 2) / 3; 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sym_verbose >= 2) 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf ("%s: Delay (GEN=%d): %u msec, %u KHz\n", 3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_name(np), gen, ms/4, f); 3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return f; 3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic unsigned sym_getfreq (struct sym_hcb *np) 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int f1, f2; 3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int gen = 8; 3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds getfreq (np, gen); /* throw away first result */ 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds f1 = getfreq (np, gen); 3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds f2 = getfreq (np, gen); 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (f1 > f2) f1 = f2; /* trust lower result */ 3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return f1; 3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get/probe chip SCSI clock frequency 3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sym_getclock (struct sym_hcb *np, int mult) 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char scntl3 = np->sv_scntl3; 3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char stest1 = np->sv_stest1; 3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned f1; 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->multiplier = 1; 3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds f1 = 40000; 3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * True with 875/895/896/895A with clock multiplier selected 3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (mult > 1 && (stest1 & (DBLEN+DBLSEL)) == DBLEN+DBLSEL) { 4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sym_verbose >= 2) 4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf ("%s: clock multiplier found\n", sym_name(np)); 4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->multiplier = mult; 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If multiplier not found or scntl3 not 7,5,3, 4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * reset chip and get frequency from general purpose timer. 4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Otherwise trust scntl3 BIOS setting. 4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->multiplier != mult || (scntl3 & 7) < 3 || !(scntl3 & 1)) { 4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_stest1, 0); /* make sure doubler is OFF */ 4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds f1 = sym_getfreq (np); 4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sym_verbose) 4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf ("%s: chip clock is %uKHz\n", sym_name(np), f1); 4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (f1 < 45000) f1 = 40000; 4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (f1 < 55000) f1 = 50000; 4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else f1 = 80000; 4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (f1 < 80000 && mult > 1) { 4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sym_verbose >= 2) 4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf ("%s: clock multiplier assumed\n", 4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_name(np)); 4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->multiplier = mult; 4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((scntl3 & 7) == 3) f1 = 40000; 4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if ((scntl3 & 7) == 5) f1 = 80000; 4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else f1 = 160000; 4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds f1 /= np->multiplier; 4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Compute controller synchronous parameters. 4381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds f1 *= np->multiplier; 4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->clock_khz = f1; 4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get/probe PCI clock frequency 4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int sym_getpciclock (struct sym_hcb *np) 4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int f = 0; 4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For now, we only need to know about the actual 4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PCI BUS clock frequency for C1010-66 chips. 4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 1 4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->features & FE_66MHZ) { 4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (1) { 4581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 4591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_stest1, SCLK); /* Use the PCI clock as SCSI clock */ 4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds f = sym_getfreq(np); 4611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_stest1, 0); 4621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 4631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->pciclk_khz = f; 4641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return f; 4661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 4671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SYMBIOS chip clock divisor table. 4701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Divisors are multiplied by 10,000,000 in order to make 4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * calculations more simple. 4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define _5M 5000000 47576789f01768bb4cef706f4c9e7e2f3f4eb8c1431Matthew Wilcoxstatic const u32 div_10M[] = {2*_5M, 3*_5M, 4*_5M, 6*_5M, 8*_5M, 12*_5M, 16*_5M}; 4761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get clock factor and sync divisor for a given 4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * synchronous factor period. 4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssym_getsync(struct sym_hcb *np, u_char dt, u_char sfac, u_char *divp, u_char *fakp) 4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 clk = np->clock_khz; /* SCSI clock frequency in kHz */ 4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int div = np->clock_divn; /* Number of divisors supported */ 4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 fak; /* Sync factor in sxfer */ 4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 per; /* Period in tenths of ns */ 4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 kpc; /* (per * clk) */ 4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int ret; 4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Compute the synchronous period in tenths of nano-seconds 4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dt && sfac <= 9) per = 125; 4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (sfac <= 10) per = 250; 4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (sfac == 11) per = 303; 4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (sfac == 12) per = 500; 4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else per = 40 * sfac; 4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = per; 5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kpc = per * clk; 5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dt) 5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kpc <<= 1; 5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For earliest C10 revision 0, we cannot use extra 5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * clocks for the setting of the SCSI clocking. 5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note that this limits the lowest sync data transfer 5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to 5 Mega-transfers per second and may result in 5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * using higher clock divisors. 5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 1 5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((np->features & (FE_C10|FE_U3EN)) == FE_C10) { 5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Look for the lowest clock divisor that allows an 5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * output speed not faster than the period. 5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (div > 0) { 5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds --div; 5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (kpc > (div_10M[div] << 2)) { 5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ++div; 5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fak = 0; /* No extra clocks */ 5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (div == np->clock_divn) { /* Are we too fast ? */ 5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -1; 5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *divp = div; 5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *fakp = fak; 5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Look for the greatest clock divisor that allows an 5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * input speed faster than the period. 5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (div-- > 0) 5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (kpc >= (div_10M[div] << 2)) break; 5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Calculate the lowest clock factor that allows an output 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * speed not faster than the period, and the max output speed. 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If fak >= 1 we will set both XCLKH_ST and XCLKH_DT. 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If fak >= 2 we will also set XCLKS_ST and XCLKS_DT. 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dt) { 5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fak = (kpc - 1) / (div_10M[div] << 1) + 1 - 2; 5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* ret = ((2+fak)*div_10M[div])/np->clock_khz; */ 5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fak = (kpc - 1) / div_10M[div] + 1 - 4; 5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* ret = ((4+fak)*div_10M[div])/np->clock_khz; */ 5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Check against our hardware limits, or bugs :). 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fak > 2) { 5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fak = 2; 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ret = -1; 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Compute and return sync parameters. 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *divp = div; 5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *fakp = fak; 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return ret; 5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SYMBIOS chips allow burst lengths of 2, 4, 8, 16, 32, 64, 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 128 transfers. All chips support at least 16 transfers 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bursts. The 825A, 875 and 895 chips support bursts of up 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to 128 transfers and the 895A and 896 support bursts of up 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to 64 transfers. All other chips support up to 16 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * transfers bursts. 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For PCI 32 bit data transfers each transfer is a DWORD. 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * It is a QUADWORD (8 bytes) for PCI 64 bit data transfers. 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We use log base 2 (burst length) as internal code, with 5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * value 0 meaning "burst disabled". 5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Burst length from burst code. 5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define burst_length(bc) (!(bc))? 0 : 1 << (bc) 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Burst code from io register bits. 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define burst_code(dmode, ctest4, ctest5) \ 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (ctest4) & 0x80? 0 : (((dmode) & 0xc0) >> 6) + ((ctest5) & 0x04) + 1 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set initial io register bits from burst code. 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6021beb6fa85ca9afaee109811a3f4a984232a32a4fHarvey Harrisonstatic inline void sym_init_burst(struct sym_hcb *np, u_char bc) 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->rv_ctest4 &= ~0x80; 6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->rv_dmode &= ~(0x3 << 6); 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->rv_ctest5 &= ~0x4; 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!bc) { 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->rv_ctest4 |= 0x80; 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds --bc; 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->rv_dmode |= ((bc & 0x3) << 6); 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->rv_ctest5 |= (bc & 0x4); 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Save initial settings of some IO registers. 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Assumed to have been set by BIOS. 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We cannot reset the chip prior to reading the 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * IO registers, since informations will be lost. 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Since the SCRIPTS processor may be running, this 6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is not safe on paper, but it seems to work quite 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * well. :) 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sym_save_initial_setting (struct sym_hcb *np) 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->sv_scntl0 = INB(np, nc_scntl0) & 0x0a; 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->sv_scntl3 = INB(np, nc_scntl3) & 0x07; 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->sv_dmode = INB(np, nc_dmode) & 0xce; 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->sv_dcntl = INB(np, nc_dcntl) & 0xa8; 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->sv_ctest3 = INB(np, nc_ctest3) & 0x01; 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->sv_ctest4 = INB(np, nc_ctest4) & 0x80; 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->sv_gpcntl = INB(np, nc_gpcntl); 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->sv_stest1 = INB(np, nc_stest1); 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->sv_stest2 = INB(np, nc_stest2) & 0x20; 6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->sv_stest4 = INB(np, nc_stest4); 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->features & FE_C10) { /* Always large DMA fifo + ultra3 */ 6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->sv_scntl4 = INB(np, nc_scntl4); 6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->sv_ctest5 = INB(np, nc_ctest5) & 0x04; 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->sv_ctest5 = INB(np, nc_ctest5) & 0x24; 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 648c2349df918cdfd47dfe6afaaeed9f504b83255d0Matthew Wilcox * Set SCSI BUS mode. 649c2349df918cdfd47dfe6afaaeed9f504b83255d0Matthew Wilcox * - LVD capable chips (895/895A/896/1010) report the current BUS mode 650c2349df918cdfd47dfe6afaaeed9f504b83255d0Matthew Wilcox * through the STEST4 IO register. 651c2349df918cdfd47dfe6afaaeed9f504b83255d0Matthew Wilcox * - For previous generation chips (825/825A/875), the user has to tell us 652c2349df918cdfd47dfe6afaaeed9f504b83255d0Matthew Wilcox * how to check against HVD, since a 100% safe algorithm is not possible. 653c2349df918cdfd47dfe6afaaeed9f504b83255d0Matthew Wilcox */ 654c2349df918cdfd47dfe6afaaeed9f504b83255d0Matthew Wilcoxstatic void sym_set_bus_mode(struct sym_hcb *np, struct sym_nvram *nvram) 655c2349df918cdfd47dfe6afaaeed9f504b83255d0Matthew Wilcox{ 656c2349df918cdfd47dfe6afaaeed9f504b83255d0Matthew Wilcox if (np->scsi_mode) 657c2349df918cdfd47dfe6afaaeed9f504b83255d0Matthew Wilcox return; 658c2349df918cdfd47dfe6afaaeed9f504b83255d0Matthew Wilcox 659c2349df918cdfd47dfe6afaaeed9f504b83255d0Matthew Wilcox np->scsi_mode = SMODE_SE; 660c2349df918cdfd47dfe6afaaeed9f504b83255d0Matthew Wilcox if (np->features & (FE_ULTRA2|FE_ULTRA3)) 661c2349df918cdfd47dfe6afaaeed9f504b83255d0Matthew Wilcox np->scsi_mode = (np->sv_stest4 & SMODE); 662c2349df918cdfd47dfe6afaaeed9f504b83255d0Matthew Wilcox else if (np->features & FE_DIFF) { 663c2349df918cdfd47dfe6afaaeed9f504b83255d0Matthew Wilcox if (SYM_SETUP_SCSI_DIFF == 1) { 664c2349df918cdfd47dfe6afaaeed9f504b83255d0Matthew Wilcox if (np->sv_scntl3) { 665c2349df918cdfd47dfe6afaaeed9f504b83255d0Matthew Wilcox if (np->sv_stest2 & 0x20) 666c2349df918cdfd47dfe6afaaeed9f504b83255d0Matthew Wilcox np->scsi_mode = SMODE_HVD; 667c2349df918cdfd47dfe6afaaeed9f504b83255d0Matthew Wilcox } else if (nvram->type == SYM_SYMBIOS_NVRAM) { 668c2349df918cdfd47dfe6afaaeed9f504b83255d0Matthew Wilcox if (!(INB(np, nc_gpreg) & 0x08)) 669c2349df918cdfd47dfe6afaaeed9f504b83255d0Matthew Wilcox np->scsi_mode = SMODE_HVD; 670c2349df918cdfd47dfe6afaaeed9f504b83255d0Matthew Wilcox } 671c2349df918cdfd47dfe6afaaeed9f504b83255d0Matthew Wilcox } else if (SYM_SETUP_SCSI_DIFF == 2) 672c2349df918cdfd47dfe6afaaeed9f504b83255d0Matthew Wilcox np->scsi_mode = SMODE_HVD; 673c2349df918cdfd47dfe6afaaeed9f504b83255d0Matthew Wilcox } 674c2349df918cdfd47dfe6afaaeed9f504b83255d0Matthew Wilcox if (np->scsi_mode == SMODE_HVD) 675c2349df918cdfd47dfe6afaaeed9f504b83255d0Matthew Wilcox np->rv_stest2 |= 0x20; 676c2349df918cdfd47dfe6afaaeed9f504b83255d0Matthew Wilcox} 677c2349df918cdfd47dfe6afaaeed9f504b83255d0Matthew Wilcox 678c2349df918cdfd47dfe6afaaeed9f504b83255d0Matthew Wilcox/* 6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Prepare io register values used by sym_start_up() 6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * according to selected and supported features. 6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int sym_prepare_setting(struct Scsi_Host *shost, struct sym_hcb *np, struct sym_nvram *nvram) 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 6845111eefa17615bdf17ca00ec2cdca16302c7697eMatthew Wilcox struct sym_data *sym_data = shost_priv(shost); 6855111eefa17615bdf17ca00ec2cdca16302c7697eMatthew Wilcox struct pci_dev *pdev = sym_data->pdev; 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char burst_max; 6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 period; 6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 690c2349df918cdfd47dfe6afaaeed9f504b83255d0Matthew Wilcox np->maxwide = (np->features & FE_WIDE) ? 1 : 0; 6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Guess the frequency of the chip's clock. 6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->features & (FE_ULTRA3 | FE_ULTRA2)) 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->clock_khz = 160000; 6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (np->features & FE_ULTRA) 6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->clock_khz = 80000; 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->clock_khz = 40000; 7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get the clock multiplier factor. 7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->features & FE_QUAD) 7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->multiplier = 4; 7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (np->features & FE_DBLR) 7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->multiplier = 2; 7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->multiplier = 1; 7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Measure SCSI clock frequency for chips 7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it may vary from assumed one. 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->features & FE_VARCLK) 7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_getclock(np, np->multiplier); 7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Divisor to be used for async (timer pre-scaler). 7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = np->clock_divn - 1; 7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (--i >= 0) { 7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (10ul * SYM_CONF_MIN_ASYNC * np->clock_khz > div_10M[i]) { 7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ++i; 7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->rv_scntl3 = i+1; 7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The C1010 uses hardwired divisors for async. 7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * So, we just throw away, the async. divisor.:-) 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->features & FE_C10) 7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->rv_scntl3 = 0; 7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Minimum synchronous period factor supported by the chip. 7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Btw, 'period' is in tenths of nanoseconds. 7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds period = (4 * div_10M[0] + np->clock_khz - 1) / np->clock_khz; 7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (period <= 250) np->minsync = 10; 7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (period <= 303) np->minsync = 11; 7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (period <= 500) np->minsync = 12; 7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else np->minsync = (period + 40 - 1) / 40; 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Check against chip SCSI standard support (SCSI-2,ULTRA,ULTRA2). 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->minsync < 25 && 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !(np->features & (FE_ULTRA|FE_ULTRA2|FE_ULTRA3))) 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->minsync = 25; 7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (np->minsync < 12 && 7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !(np->features & (FE_ULTRA2|FE_ULTRA3))) 7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->minsync = 12; 7581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Maximum synchronous period factor supported by the chip. 7611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds period = (11 * div_10M[np->clock_divn - 1]) / (4 * np->clock_khz); 7631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->maxsync = period > 2540 ? 254 : period / 10; 7641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If chip is a C1010, guess the sync limits in DT mode. 7671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((np->features & (FE_C10|FE_ULTRA3)) == (FE_C10|FE_ULTRA3)) { 7691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->clock_khz == 160000) { 7701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->minsync_dt = 9; 7711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->maxsync_dt = 50; 7721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->maxoffs_dt = nvram->type ? 62 : 31; 7731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 64 bit addressing (895A/896/1010) ? 7781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->features & FE_DAC) { 7804d85b471593d03e141f9160a58574b9204363267Matthew Wilcox if (!use_dac(np)) 7814d85b471593d03e141f9160a58574b9204363267Matthew Wilcox np->rv_ccntl1 |= (DDAC); 7824d85b471593d03e141f9160a58574b9204363267Matthew Wilcox else if (SYM_CONF_DMA_ADDRESSING_MODE == 1) 7834d85b471593d03e141f9160a58574b9204363267Matthew Wilcox np->rv_ccntl1 |= (XTIMOD | EXTIBMV); 7844d85b471593d03e141f9160a58574b9204363267Matthew Wilcox else if (SYM_CONF_DMA_ADDRESSING_MODE == 2) 7854d85b471593d03e141f9160a58574b9204363267Matthew Wilcox np->rv_ccntl1 |= (0 | EXTIBMV); 7861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 7871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Phase mismatch handled by SCRIPTS (895A/896/1010) ? 7901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->features & FE_NOPM) 7921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->rv_ccntl0 |= (ENPMJ); 7931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * C1010-33 Errata: Part Number:609-039638 (rev. 1) is fixed. 7961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * In dual channel mode, contention occurs if internal cycles 7971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * are used. Disable internal cycles. 7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 7995111eefa17615bdf17ca00ec2cdca16302c7697eMatthew Wilcox if (pdev->device == PCI_DEVICE_ID_LSI_53C1010_33 && 8005111eefa17615bdf17ca00ec2cdca16302c7697eMatthew Wilcox pdev->revision < 0x1) 8011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->rv_ccntl0 |= DILS; 8021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Select burst length (dwords) 8051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds burst_max = SYM_SETUP_BURST_ORDER; 8071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (burst_max == 255) 8081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds burst_max = burst_code(np->sv_dmode, np->sv_ctest4, 8091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->sv_ctest5); 8101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (burst_max > 7) 8111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds burst_max = 7; 8121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (burst_max > np->maxburst) 8131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds burst_max = np->maxburst; 8141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * DEL 352 - 53C810 Rev x11 - Part Number 609-0392140 - ITEM 2. 8171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This chip and the 860 Rev 1 may wrongly use PCI cache line 8181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * based transactions on LOAD/STORE instructions. So we have 8191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to prevent these chips from using such PCI transactions in 8201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this driver. The generic ncr driver that does not use 8211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * LOAD/STORE instructions does not need this work-around. 8221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8235111eefa17615bdf17ca00ec2cdca16302c7697eMatthew Wilcox if ((pdev->device == PCI_DEVICE_ID_NCR_53C810 && 8245111eefa17615bdf17ca00ec2cdca16302c7697eMatthew Wilcox pdev->revision >= 0x10 && pdev->revision <= 0x11) || 8255111eefa17615bdf17ca00ec2cdca16302c7697eMatthew Wilcox (pdev->device == PCI_DEVICE_ID_NCR_53C860 && 8265111eefa17615bdf17ca00ec2cdca16302c7697eMatthew Wilcox pdev->revision <= 0x1)) 8271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->features &= ~(FE_WRIE|FE_ERL|FE_ERMP); 8281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Select all supported special features. 8311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we are using on-board RAM for scripts, prefetch (PFEN) 8321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * does not help, but burst op fetch (BOF) does. 8331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Disabling PFEN makes sure BOF will be used. 8341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->features & FE_ERL) 8361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->rv_dmode |= ERL; /* Enable Read Line */ 8371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->features & FE_BOF) 8381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->rv_dmode |= BOF; /* Burst Opcode Fetch */ 8391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->features & FE_ERMP) 8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->rv_dmode |= ERMP; /* Enable Read Multiple */ 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 1 8421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((np->features & FE_PFEN) && !np->ram_ba) 8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->features & FE_PFEN) 8451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->rv_dcntl |= PFEN; /* Prefetch Enable */ 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->features & FE_CLSE) 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->rv_dcntl |= CLSE; /* Cache Line Size Enable */ 8491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->features & FE_WRIE) 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->rv_ctest3 |= WRIE; /* Write and Invalidate */ 8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->features & FE_DFS) 8521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->rv_ctest5 |= DFS; /* Dma Fifo Size */ 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Select some other 8561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->rv_ctest4 |= MPEE; /* Master parity checking */ 8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->rv_scntl0 |= 0x0a; /* full arb., ena parity, par->ATN */ 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get parity checking, host ID and verbose mode from NVRAM 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->myaddr = 255; 864c2349df918cdfd47dfe6afaaeed9f504b83255d0Matthew Wilcox np->scsi_mode = 0; 8651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_nvram_setup_host(shost, np, nvram); 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get SCSI addr of host adapter (set by bios?). 8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->myaddr == 255) { 8711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->myaddr = INB(np, nc_scid) & 0x07; 8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!np->myaddr) 8731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->myaddr = SYM_SETUP_HOST_ID; 8741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Prepare initial io register bits for burst length 8781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_init_burst(np, burst_max); 8801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 881c2349df918cdfd47dfe6afaaeed9f504b83255d0Matthew Wilcox sym_set_bus_mode(np, nvram); 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set LED support from SCRIPTS. 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ignore this feature for boards known to use a 8861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * specific GPIO wiring and for the 895A, 896 8871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and 1010 that drive the LED directly. 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((SYM_SETUP_SCSI_LED || 8901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (nvram->type == SYM_SYMBIOS_NVRAM || 8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (nvram->type == SYM_TEKRAM_NVRAM && 8925111eefa17615bdf17ca00ec2cdca16302c7697eMatthew Wilcox pdev->device == PCI_DEVICE_ID_NCR_53C895))) && 8931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !(np->features & FE_LEDC) && !(np->sv_gpcntl & 0x01)) 8941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->features |= FE_LED0; 8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 8971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set irq mode. 8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch(SYM_SETUP_IRQ_MODE & 3) { 9001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 2: 9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->rv_dcntl |= IRQM; 9021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 1: 9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->rv_dcntl |= (np->sv_dcntl & IRQM); 9051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 9071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 9081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 9111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Configure targets according to driver setup. 9121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If NVRAM present get targets setup from NVRAM. 9131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0 ; i < SYM_CONF_MAX_TARGET ; i++) { 9151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_tcb *tp = &np->target[i]; 9161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->usrflags |= (SYM_DISC_ENABLED | SYM_TAGS_ENABLED); 9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->usrtags = SYM_SETUP_MAX_TAG; 91923ff51e9fe24f98c1053ac1cdded434012eee342Matthew Wilcox tp->usr_width = np->maxwide; 92023ff51e9fe24f98c1053ac1cdded434012eee342Matthew Wilcox tp->usr_period = 9; 9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 922b37df48923b76155de2a728e1155ed263dba5f53Matthew Wilcox sym_nvram_setup_target(tp, i, nvram); 9231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!tp->usrtags) 9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->usrflags &= ~SYM_TAGS_ENABLED; 9261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 9291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Let user know about the settings. 9301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf("%s: %s, ID %d, Fast-%d, %s, %s\n", sym_name(np), 9321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_nvram_type(nvram), np->myaddr, 9331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (np->features & FE_ULTRA3) ? 80 : 9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (np->features & FE_ULTRA2) ? 40 : 9351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (np->features & FE_ULTRA) ? 20 : 10, 9361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_scsi_bus_mode(np->scsi_mode), 9371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (np->rv_scntl0 & 0xa) ? "parity checking" : "NO parity"); 9381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 9391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Tell him more on demand. 9401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sym_verbose) { 9421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf("%s: %s IRQ line driver%s\n", 9431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_name(np), 9441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->rv_dcntl & IRQM ? "totem pole" : "open drain", 9451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->ram_ba ? ", using on-chip SRAM" : ""); 9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf("%s: using %s firmware.\n", sym_name(np), np->fw_name); 9471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->features & FE_NOPM) 9481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf("%s: handling phase mismatch from SCRIPTS.\n", 9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_name(np)); 9501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * And still more. 9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sym_verbose >= 2) { 9551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf ("%s: initial SCNTL3/DMODE/DCNTL/CTEST3/4/5 = " 9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "(hex) %02x/%02x/%02x/%02x/%02x/%02x\n", 9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_name(np), np->sv_scntl3, np->sv_dmode, np->sv_dcntl, 9581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->sv_ctest3, np->sv_ctest4, np->sv_ctest5); 9591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf ("%s: final SCNTL3/DMODE/DCNTL/CTEST3/4/5 = " 9611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "(hex) %02x/%02x/%02x/%02x/%02x/%02x\n", 9621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_name(np), np->rv_scntl3, np->rv_dmode, np->rv_dcntl, 9631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->rv_ctest3, np->rv_ctest4, np->rv_ctest5); 9641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 9671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 9701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Test the pci bus snoop logic :-( 9711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 9721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Has to be called with interrupts disabled. 9731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9741f61d82490a26dbcde903b33e24f6d11b758b64cMatthew Wilcox#ifdef CONFIG_SCSI_SYM53C8XX_MMIO 9751f61d82490a26dbcde903b33e24f6d11b758b64cMatthew Wilcoxstatic int sym_regtest(struct sym_hcb *np) 9761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 9771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds register volatile u32 data; 9781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 9791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * chip registers may NOT be cached. 9801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * write 0xffffffff to a read only register area, 9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and try to read it back. 9821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 9831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data = 0xffffffff; 9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL(np, nc_dstat, data); 9851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds data = INL(np, nc_dstat); 9861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 1 9871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (data == 0xffffffff) { 9881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 9891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((data & 0xe2f0fffd) != 0x02000080) { 9901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 9911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf ("CACHE TEST FAILED: reg dstat-sstat2 readback %x.\n", 9921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned) data); 9931f61d82490a26dbcde903b33e24f6d11b758b64cMatthew Wilcox return 0x10; 9941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9951f61d82490a26dbcde903b33e24f6d11b758b64cMatthew Wilcox return 0; 9961f61d82490a26dbcde903b33e24f6d11b758b64cMatthew Wilcox} 9971f61d82490a26dbcde903b33e24f6d11b758b64cMatthew Wilcox#else 9981f61d82490a26dbcde903b33e24f6d11b758b64cMatthew Wilcoxstatic inline int sym_regtest(struct sym_hcb *np) 9991f61d82490a26dbcde903b33e24f6d11b758b64cMatthew Wilcox{ 10001f61d82490a26dbcde903b33e24f6d11b758b64cMatthew Wilcox return 0; 10011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 10031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 10041f61d82490a26dbcde903b33e24f6d11b758b64cMatthew Wilcoxstatic int sym_snooptest(struct sym_hcb *np) 10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 10061f61d82490a26dbcde903b33e24f6d11b758b64cMatthew Wilcox u32 sym_rd, sym_wr, sym_bk, host_rd, host_wr, pc, dstat; 10071f61d82490a26dbcde903b33e24f6d11b758b64cMatthew Wilcox int i, err; 10081f61d82490a26dbcde903b33e24f6d11b758b64cMatthew Wilcox 10091f61d82490a26dbcde903b33e24f6d11b758b64cMatthew Wilcox err = sym_regtest(np); 10101f61d82490a26dbcde903b33e24f6d11b758b64cMatthew Wilcox if (err) 10111f61d82490a26dbcde903b33e24f6d11b758b64cMatthew Wilcox return err; 10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsrestart_test: 10131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 10141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Enable Master Parity Checking as we intend 10151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to enable it for normal operations. 10161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_ctest4, (np->rv_ctest4 & MPEE)); 10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 10191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * init 10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pc = SCRIPTZ_BA(np, snooptest); 10221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host_wr = 1; 10231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_wr = 2; 10241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 10251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set memory and register. 10261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->scratch = cpu_to_scr(host_wr); 10281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL(np, nc_temp, sym_wr); 10291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 10301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Start script (exchange values) 10311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL(np, nc_dsa, np->hcb_ba); 10331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL_DSP(np, pc); 10341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 10351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wait 'til done (with timeout) 10361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i=0; i<SYM_SNOOP_TIMEOUT; i++) 10381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (INB(np, nc_istat) & (INTF|SIP|DIP)) 10391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 10401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i>=SYM_SNOOP_TIMEOUT) { 10411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf ("CACHE TEST FAILED: timeout.\n"); 10421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (0x20); 10431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 10451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Check for fatal DMA errors. 10461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dstat = INB(np, nc_dstat); 10481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 1 /* Band aiding for broken hardwares that fail PCI parity */ 10491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((dstat & MDPE) && (np->rv_ctest4 & MPEE)) { 10501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf ("%s: PCI DATA PARITY ERROR DETECTED - " 10511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "DISABLING MASTER DATA PARITY CHECKING.\n", 10521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_name(np)); 10531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->rv_ctest4 &= ~MPEE; 10541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto restart_test; 10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 10571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dstat & (MDPE|BF|IID)) { 10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf ("CACHE TEST FAILED: DMA error (dstat=0x%02x).", dstat); 10591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (0x80); 10601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 10621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Save termination position. 10631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pc = INL(np, nc_dsp); 10651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 10661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Read memory and register. 10671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds host_rd = scr_to_cpu(np->scratch); 10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_rd = INL(np, nc_scratcha); 10701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_bk = INL(np, nc_temp); 10711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Check termination position. 10731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pc != SCRIPTZ_BA(np, snoopend)+8) { 10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf ("CACHE TEST FAILED: script execution failed.\n"); 10761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf ("start=%08lx, pc=%08lx, end=%08lx\n", 10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (u_long) SCRIPTZ_BA(np, snooptest), (u_long) pc, 10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (u_long) SCRIPTZ_BA(np, snoopend) +8); 10791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (0x40); 10801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 10821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Show results. 10831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 10841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (host_wr != sym_rd) { 10851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf ("CACHE TEST FAILED: host wrote %d, chip read %d.\n", 10861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (int) host_wr, (int) sym_rd); 10871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err |= 1; 10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (host_rd != sym_wr) { 10901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf ("CACHE TEST FAILED: chip wrote %d, host read %d.\n", 10911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (int) sym_wr, (int) host_rd); 10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err |= 2; 10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sym_bk != sym_wr) { 10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf ("CACHE TEST FAILED: chip wrote %d, read back %d.\n", 10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (int) sym_wr, (int) sym_bk); 10971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds err |= 4; 10981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11001f61d82490a26dbcde903b33e24f6d11b758b64cMatthew Wilcox return err; 11011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 11041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * log message for real hard errors 11051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 11061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sym0 targ 0?: ERROR (ds:si) (so-si-sd) (sx/s3/s4) @ name (dsp:dbc). 11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * reg: r0 r1 r2 r3 r4 r5 r6 ..... rf. 11081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 11091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * exception register: 11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ds: dstat 11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * si: sist 11121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SCSI bus lines: 11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * so: control lines as driven by chip. 11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * si: control lines as seen by chip. 11161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sd: scsi data lines as seen by chip. 11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 11181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * wide/fastmode: 11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sx: sxfer (see the manual) 11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * s3: scntl3 (see the manual) 11211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * s4: scntl4 (see the manual) 11221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * current script command: 11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dsp: script address (relative to start of script). 11251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dbc: first word of script command. 11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * First 24 register of the chip: 11281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * r0..rf 11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 11305111eefa17615bdf17ca00ec2cdca16302c7697eMatthew Wilcoxstatic void sym_log_hard_error(struct Scsi_Host *shost, u_short sist, u_char dstat) 11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 11325111eefa17615bdf17ca00ec2cdca16302c7697eMatthew Wilcox struct sym_hcb *np = sym_get_hcb(shost); 11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 dsp; 11341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int script_ofs; 11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int script_size; 11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds char *script_name; 11371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char *script_base; 11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dsp = INL(np, nc_dsp); 11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dsp > np->scripta_ba && 11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dsp <= np->scripta_ba + np->scripta_sz) { 11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds script_ofs = dsp - np->scripta_ba; 11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds script_size = np->scripta_sz; 11461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds script_base = (u_char *) np->scripta0; 11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds script_name = "scripta"; 11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (np->scriptb_ba < dsp && 11501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dsp <= np->scriptb_ba + np->scriptb_sz) { 11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds script_ofs = dsp - np->scriptb_ba; 11521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds script_size = np->scriptb_sz; 11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds script_base = (u_char *) np->scriptb0; 11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds script_name = "scriptb"; 11551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 11561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds script_ofs = dsp; 11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds script_size = 0; 11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds script_base = NULL; 11591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds script_name = "mem"; 11601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf ("%s:%d: ERROR (%x:%x) (%x-%x-%x) (%x/%x/%x) @ (%s %x:%08x).\n", 11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_name(np), (unsigned)INB(np, nc_sdid)&0x0f, dstat, sist, 11641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned)INB(np, nc_socl), (unsigned)INB(np, nc_sbcl), 11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned)INB(np, nc_sbdl), (unsigned)INB(np, nc_sxfer), 11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned)INB(np, nc_scntl3), 11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (np->features & FE_C10) ? (unsigned)INB(np, nc_scntl4) : 0, 11681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds script_name, script_ofs, (unsigned)INL(np, nc_dbc)); 11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (((script_ofs & 3) == 0) && 11711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned)script_ofs < script_size) { 11721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf ("%s: script cmd = %08x\n", sym_name(np), 11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scr_to_cpu((int) *(u32 *)(script_base + script_ofs))); 11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1176d68cd75992f95d6977956fb227f02e6d532f3d26Linas Vepstas printf("%s: regdump:", sym_name(np)); 1177d68cd75992f95d6977956fb227f02e6d532f3d26Linas Vepstas for (i = 0; i < 24; i++) 1178d68cd75992f95d6977956fb227f02e6d532f3d26Linas Vepstas printf(" %02x", (unsigned)INB_OFF(np, i)); 1179d68cd75992f95d6977956fb227f02e6d532f3d26Linas Vepstas printf(".\n"); 11801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 11821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PCI BUS error. 11831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 11841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dstat & (MDPE|BF)) 11855111eefa17615bdf17ca00ec2cdca16302c7697eMatthew Wilcox sym_log_bus_error(shost); 11861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11885111eefa17615bdf17ca00ec2cdca16302c7697eMatthew Wilcoxvoid sym_dump_registers(struct Scsi_Host *shost) 1189d68cd75992f95d6977956fb227f02e6d532f3d26Linas Vepstas{ 11905111eefa17615bdf17ca00ec2cdca16302c7697eMatthew Wilcox struct sym_hcb *np = sym_get_hcb(shost); 1191d68cd75992f95d6977956fb227f02e6d532f3d26Linas Vepstas u_short sist; 1192d68cd75992f95d6977956fb227f02e6d532f3d26Linas Vepstas u_char dstat; 1193d68cd75992f95d6977956fb227f02e6d532f3d26Linas Vepstas 1194d68cd75992f95d6977956fb227f02e6d532f3d26Linas Vepstas sist = INW(np, nc_sist); 1195d68cd75992f95d6977956fb227f02e6d532f3d26Linas Vepstas dstat = INB(np, nc_dstat); 11965111eefa17615bdf17ca00ec2cdca16302c7697eMatthew Wilcox sym_log_hard_error(shost, sist, dstat); 1197d68cd75992f95d6977956fb227f02e6d532f3d26Linas Vepstas} 1198d68cd75992f95d6977956fb227f02e6d532f3d26Linas Vepstas 11991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sym_chip sym_dev_table[] = { 12001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {PCI_DEVICE_ID_NCR_53C810, 0x0f, "810", 4, 8, 4, 64, 12011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FE_ERL} 12021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds , 12031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef SYM_DEBUG_GENERIC_SUPPORT 12041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {PCI_DEVICE_ID_NCR_53C810, 0xff, "810a", 4, 8, 4, 1, 12051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FE_BOF} 12061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds , 12071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 12081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {PCI_DEVICE_ID_NCR_53C810, 0xff, "810a", 4, 8, 4, 1, 12091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FE_CACHE_SET|FE_LDSTR|FE_PFEN|FE_BOF} 12101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds , 12111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 12121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {PCI_DEVICE_ID_NCR_53C815, 0xff, "815", 4, 8, 4, 64, 12131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FE_BOF|FE_ERL} 12141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds , 12151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {PCI_DEVICE_ID_NCR_53C825, 0x0f, "825", 6, 8, 4, 64, 12161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FE_WIDE|FE_BOF|FE_ERL|FE_DIFF} 12171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds , 12181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {PCI_DEVICE_ID_NCR_53C825, 0xff, "825a", 6, 8, 4, 2, 12191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FE_WIDE|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM|FE_DIFF} 12201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds , 12211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {PCI_DEVICE_ID_NCR_53C860, 0xff, "860", 4, 8, 5, 1, 12221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FE_ULTRA|FE_CACHE_SET|FE_BOF|FE_LDSTR|FE_PFEN} 12231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds , 12241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {PCI_DEVICE_ID_NCR_53C875, 0x01, "875", 6, 16, 5, 2, 12251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FE_WIDE|FE_ULTRA|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| 12261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FE_RAM|FE_DIFF|FE_VARCLK} 12271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds , 12281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {PCI_DEVICE_ID_NCR_53C875, 0xff, "875", 6, 16, 5, 2, 12291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| 12301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FE_RAM|FE_DIFF|FE_VARCLK} 12311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds , 12321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {PCI_DEVICE_ID_NCR_53C875J, 0xff, "875J", 6, 16, 5, 2, 12331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| 12341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FE_RAM|FE_DIFF|FE_VARCLK} 12351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds , 12361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {PCI_DEVICE_ID_NCR_53C885, 0xff, "885", 6, 16, 5, 2, 12371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| 12381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FE_RAM|FE_DIFF|FE_VARCLK} 12391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds , 12401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef SYM_DEBUG_GENERIC_SUPPORT 12411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {PCI_DEVICE_ID_NCR_53C895, 0xff, "895", 6, 31, 7, 2, 12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS| 12431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FE_RAM|FE_LCKFRQ} 12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds , 12451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {PCI_DEVICE_ID_NCR_53C895, 0xff, "895", 6, 31, 7, 2, 12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| 12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FE_RAM|FE_LCKFRQ} 12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds , 12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {PCI_DEVICE_ID_NCR_53C896, 0xff, "896", 6, 31, 7, 4, 12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| 12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_LCKFRQ} 12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds , 12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {PCI_DEVICE_ID_LSI_53C895A, 0xff, "895a", 6, 31, 7, 4, 12561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| 12571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FE_RAM|FE_RAM8K|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_LCKFRQ} 12581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds , 12591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {PCI_DEVICE_ID_LSI_53C875A, 0xff, "875a", 6, 31, 7, 4, 12601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FE_WIDE|FE_ULTRA|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| 12611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FE_RAM|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_LCKFRQ} 12621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds , 12631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {PCI_DEVICE_ID_LSI_53C1010_33, 0x00, "1010-33", 6, 31, 7, 8, 12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FE_WIDE|FE_ULTRA3|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFBC|FE_LDSTR|FE_PFEN| 12651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_CRC| 12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FE_C10} 12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds , 12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {PCI_DEVICE_ID_LSI_53C1010_33, 0xff, "1010-33", 6, 31, 7, 8, 12691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FE_WIDE|FE_ULTRA3|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFBC|FE_LDSTR|FE_PFEN| 12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_CRC| 12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FE_C10|FE_U3EN} 12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds , 12731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {PCI_DEVICE_ID_LSI_53C1010_66, 0xff, "1010-66", 6, 31, 7, 8, 12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FE_WIDE|FE_ULTRA3|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFBC|FE_LDSTR|FE_PFEN| 12751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_66MHZ|FE_CRC| 12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FE_C10|FE_U3EN} 12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds , 12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {PCI_DEVICE_ID_LSI_53C1510, 0xff, "1510d", 6, 31, 7, 4, 12791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN| 12801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FE_RAM|FE_IO256|FE_LEDC} 12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 12821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12836391a11375de5e2bb1eb8481e54619761dc65d9fTobias Klauser#define sym_num_devs (ARRAY_SIZE(sym_dev_table)) 12841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Look up the chip table. 12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Return a pointer to the chip entry if found, 12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * zero otherwise. 12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct sym_chip * 12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssym_lookup_chip_table (u_short device_id, u_char revision) 12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_chip *chip; 12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < sym_num_devs; i++) { 12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds chip = &sym_dev_table[i]; 12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (device_id != chip->device_id) 13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (revision > chip->revision_id) 13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return chip; 13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if SYM_CONF_DMA_ADDRESSING_MODE == 2 13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Lookup the 64 bit DMA segments map. 13121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This is only used if the direct mapping 13131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * has been unsuccessful. 13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint sym_lookup_dmap(struct sym_hcb *np, u32 h, int s) 13161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13194d85b471593d03e141f9160a58574b9204363267Matthew Wilcox if (!use_dac(np)) 13201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto weird; 13211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Look up existing mappings */ 13231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = SYM_DMAP_SIZE-1; i > 0; i--) { 13241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (h == np->dmap_bah[i]) 13251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return i; 13261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* If direct mapping is free, get it */ 13281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!np->dmap_bah[s]) 13291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto new; 13301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Collision -> lookup free mappings */ 13311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (s = SYM_DMAP_SIZE-1; s > 0; s--) { 13321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!np->dmap_bah[s]) 13331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto new; 13341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsweird: 13361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds panic("sym: ran out of 64 bit DMA segment registers"); 13371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 13381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsnew: 13391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->dmap_bah[s] = h; 13401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->dmap_dirty = 1; 13411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return s; 13421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 13451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Update IO registers scratch C..R so they will be 13461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in sync. with queued CCB expectations. 13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sym_update_dmap_regs(struct sym_hcb *np) 13491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int o, i; 13511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!np->dmap_dirty) 13531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 13541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds o = offsetof(struct sym_reg, nc_scrx[0]); 13551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < SYM_DMAP_SIZE; i++) { 13561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL_OFF(np, o, np->dmap_bah[i]); 13571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds o += 4; 13581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->dmap_dirty = 0; 13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Enforce all the fiddly SPI rules and the chip limitations */ 13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sym_check_goals(struct sym_hcb *np, struct scsi_target *starget, 13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_trans *goal) 13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 13671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!spi_support_wide(starget)) 13681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goal->width = 0; 13691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!spi_support_sync(starget)) { 13711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goal->iu = 0; 13721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goal->dt = 0; 13731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goal->qas = 0; 13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goal->offset = 0; 13751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 13761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (spi_support_dt(starget)) { 13791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (spi_support_dt_only(starget)) 13801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goal->dt = 1; 13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (goal->offset == 0) 13831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goal->dt = 0; 13841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goal->dt = 0; 13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Some targets fail to properly negotiate DT in SE mode */ 13891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((np->scsi_mode != SMODE_LVD) || !(np->features & FE_U3EN)) 13901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goal->dt = 0; 13911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (goal->dt) { 13931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* all DT transfers must be wide */ 13941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goal->width = 1; 13951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (goal->offset > np->maxoffs_dt) 13961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goal->offset = np->maxoffs_dt; 13971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (goal->period < np->minsync_dt) 13981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goal->period = np->minsync_dt; 13991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (goal->period > np->maxsync_dt) 14001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goal->period = np->maxsync_dt; 14011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 14021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goal->iu = goal->qas = 0; 14031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (goal->offset > np->maxoffs) 14041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goal->offset = np->maxoffs; 14051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (goal->period < np->minsync) 14061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goal->period = np->minsync; 14071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (goal->period > np->maxsync) 14081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goal->period = np->maxsync; 14091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 14131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Prepare the next negotiation message if needed. 14141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 14151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Fill in the part of message buffer that contains the 14161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * negotiation and the nego_status field of the CCB. 14171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Returns the size of the message in bytes. 14181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int sym_prepare_nego(struct sym_hcb *np, struct sym_ccb *cp, u_char *msgptr) 14201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_tcb *tp = &np->target[cp->target]; 142253222b906903fd861dc24ebccfa07ee125941313Matthew Wilcox struct scsi_target *starget = tp->starget; 14231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_trans *goal = &tp->tgoal; 14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int msglen = 0; 14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int nego; 14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_check_goals(np, starget, goal); 14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Many devices implement PPR in a buggy way, so only use it if we 14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * really want to. 14321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 143349799fee82b4f78c45b1926be24e45b5cf667083Aaro Koskinen if (goal->renego == NS_PPR || (goal->offset && 143449799fee82b4f78c45b1926be24e45b5cf667083Aaro Koskinen (goal->iu || goal->dt || goal->qas || (goal->period < 0xa)))) { 14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nego = NS_PPR; 143649799fee82b4f78c45b1926be24e45b5cf667083Aaro Koskinen } else if (goal->renego == NS_WIDE || goal->width) { 14371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nego = NS_WIDE; 143849799fee82b4f78c45b1926be24e45b5cf667083Aaro Koskinen } else if (goal->renego == NS_SYNC || goal->offset) { 14391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nego = NS_SYNC; 14401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 14411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goal->check_nego = 0; 14421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nego = 0; 14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (nego) { 14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case NS_SYNC: 14476ea3c0b2dac0d6a857d6bc010e544f4c901fff78Matthew Wilcox msglen += spi_populate_sync_msg(msgptr + msglen, goal->period, 14486ea3c0b2dac0d6a857d6bc010e544f4c901fff78Matthew Wilcox goal->offset); 14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case NS_WIDE: 14516ea3c0b2dac0d6a857d6bc010e544f4c901fff78Matthew Wilcox msglen += spi_populate_width_msg(msgptr + msglen, goal->width); 14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case NS_PPR: 14546ea3c0b2dac0d6a857d6bc010e544f4c901fff78Matthew Wilcox msglen += spi_populate_ppr_msg(msgptr + msglen, goal->period, 14556ea3c0b2dac0d6a857d6bc010e544f4c901fff78Matthew Wilcox goal->offset, goal->width, 14566ea3c0b2dac0d6a857d6bc010e544f4c901fff78Matthew Wilcox (goal->iu ? PPR_OPT_IU : 0) | 14571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (goal->dt ? PPR_OPT_DT : 0) | 14586ea3c0b2dac0d6a857d6bc010e544f4c901fff78Matthew Wilcox (goal->qas ? PPR_OPT_QAS : 0)); 14591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 14601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->nego_status = nego; 14631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (nego) { 14651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->nego_cp = cp; /* Keep track a nego will be performed */ 14661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (DEBUG_FLAGS & DEBUG_NEGO) { 14671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_print_nego_msg(np, cp->target, 14681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nego == NS_SYNC ? "sync msgout" : 14691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nego == NS_WIDE ? "wide msgout" : 14701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "ppr msgout", msgptr); 14711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return msglen; 14751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 14781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Insert a job into the start queue. 14791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14803bea15a76eecc03729bf74d6ab2a1f849c08423eMatthew Wilcoxvoid sym_put_start_queue(struct sym_hcb *np, struct sym_ccb *cp) 14811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 14821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_short qidx; 14831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef SYM_CONF_IARB_SUPPORT 14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the previously queued CCB is not yet done, 14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * set the IARB hint. The SCRIPTS will go with IARB 14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for this job when starting the previous one. 14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We leave devices a chance to win arbitration by 14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * not using more than 'iarb_max' consecutive 14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * immediate arbitrations. 14921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 14931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->last_cp && np->iarb_count < np->iarb_max) { 14941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->last_cp->host_flags |= HF_HINT_IARB; 14951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ++np->iarb_count; 14961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 14971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 14981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->iarb_count = 0; 14991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->last_cp = cp; 15001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 15011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if SYM_CONF_DMA_ADDRESSING_MODE == 2 15031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 15041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Make SCRIPTS aware of the 64 bit DMA 15051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * segment registers not being up-to-date. 15061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->dmap_dirty) 15081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->host_xflags |= HX_DMAP_DIRTY; 15091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 15101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 15121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Insert first the idle task and then our job. 15131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The MBs should ensure proper ordering. 15141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qidx = np->squeueput + 2; 15161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (qidx >= MAX_QUEUE*2) qidx = 0; 15171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->squeue [qidx] = cpu_to_scr(np->idletask_ba); 15191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MEMORY_WRITE_BARRIER(); 15201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->squeue [np->squeueput] = cpu_to_scr(cp->ccb_ba); 15211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->squeueput = qidx; 15231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (DEBUG_FLAGS & DEBUG_QUEUE) 15253fb364e089e05c35ead55a08d56d3004193681f6Matthew Wilcox scmd_printk(KERN_DEBUG, cp->cmd, "queuepos=%d\n", 15263fb364e089e05c35ead55a08d56d3004193681f6Matthew Wilcox np->squeueput); 15271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 15291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Script processor may be waiting for reselect. 15301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wake it up. 15311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MEMORY_WRITE_BARRIER(); 15331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_istat, SIGP|np->istat_sem); 15341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING 15371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 15381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Start next ready-to-start CCBs. 15391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid sym_start_next_ccbs(struct sym_hcb *np, struct sym_lcb *lp, int maxn) 15411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SYM_QUEHEAD *qp; 15431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_ccb *cp; 15441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 15461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Paranoia, as usual. :-) 15471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds assert(!lp->started_tags || !lp->started_no_tag); 15491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 15511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Try to start as many commands as asked by caller. 15521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Prevent from having both tagged and untagged 15531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * commands queued to the device at the same time. 15541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (maxn--) { 15561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qp = sym_remque_head(&lp->waiting_ccbq); 15571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!qp) 15581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 15591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp = sym_que_entry(qp, struct sym_ccb, link2_ccbq); 15601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp->tag != NO_TAG) { 15611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lp->started_no_tag || 15621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->started_tags >= lp->started_max) { 15631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_insque_head(qp, &lp->waiting_ccbq); 15641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 15651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->itlq_tbl[cp->tag] = cpu_to_scr(cp->ccb_ba); 15671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->head.resel_sa = 15681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cpu_to_scr(SCRIPTA_BA(np, resel_tag)); 15691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ++lp->started_tags; 15701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 15711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lp->started_no_tag || lp->started_tags) { 15721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_insque_head(qp, &lp->waiting_ccbq); 15731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 15741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->head.itl_task_sa = cpu_to_scr(cp->ccb_ba); 15761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->head.resel_sa = 15771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cpu_to_scr(SCRIPTA_BA(np, resel_no_tag)); 15781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ++lp->started_no_tag; 15791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->started = 1; 15811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_insque_tail(qp, &lp->started_ccbq); 15821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_put_start_queue(np, cp); 15831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 15841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 15851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif /* SYM_OPT_HANDLE_DEVICE_QUEUEING */ 15861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 15871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 15881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The chip may have completed jobs. Look at the DONE QUEUE. 15891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 15901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * On paper, memory read barriers may be needed here to 15911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * prevent out of order LOADs by the CPU from having 15921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * prefetched stale data prior to DMA having occurred. 15931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 15941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int sym_wakeup_done (struct sym_hcb *np) 15951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 15961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_ccb *cp; 15971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, n; 15981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 dsa; 15991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds n = 0; 16011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = np->dqueueget; 16021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* MEMORY_READ_BARRIER(); */ 16041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (1) { 16051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dsa = scr_to_cpu(np->dqueue[i]); 16061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dsa) 16071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 16081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->dqueue[i] = 0; 16091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((i = i+2) >= MAX_QUEUE*2) 16101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = 0; 16111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp = sym_ccb_from_dsa(np, dsa); 16131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp) { 16141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MEMORY_READ_BARRIER(); 16151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_complete_ok (np, cp); 16161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ++n; 16171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 16191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf ("%s: bad DSA (%x) in done queue.\n", 16201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_name(np), (u_int) dsa); 16211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->dqueueget = i; 16231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return n; 16251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 16281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Complete all CCBs queued to the COMP queue. 16291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 16301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * These CCBs are assumed: 16311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - Not to be referenced either by devices or 16321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SCRIPTS-related queues and datas. 16331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - To have to be completed with an error condition 16341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * or requeued. 16351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 16361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The device queue freeze count is incremented 16371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for each CCB that does not prevent this. 16381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This function is called when all CCBs involved 16391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in error handling/recovery have been reaped. 16401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sym_flush_comp_queue(struct sym_hcb *np, int cam_status) 16421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SYM_QUEHEAD *qp; 16441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_ccb *cp; 16451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1646172c122df5186e7cbd413d61757ff90267331002Harvey Harrison while ((qp = sym_remque_head(&np->comp_ccbq)) != NULL) { 16471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scsi_cmnd *cmd; 16481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); 16491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_insque_tail(&cp->link_ccbq, &np->busy_ccbq); 16501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Leave quiet CCBs waiting for resources */ 16511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp->host_status == HS_WAIT) 16521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 16531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd = cp->cmd; 16541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cam_status) 16551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_set_cam_status(cmd, cam_status); 16561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING 165753222b906903fd861dc24ebccfa07ee125941313Matthew Wilcox if (sym_get_cam_status(cmd) == DID_SOFT_ERROR) { 16581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_tcb *tp = &np->target[cp->target]; 16591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_lcb *lp = sym_lp(tp, cp->lun); 16601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lp) { 16611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_remque(&cp->link2_ccbq); 16621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_insque_tail(&cp->link2_ccbq, 16631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &lp->waiting_ccbq); 16641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp->started) { 16651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp->tag != NO_TAG) 16661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds --lp->started_tags; 16671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 16681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds --lp->started_no_tag; 16691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->started = 0; 16721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 16731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 16751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_free_ccb(np, cp); 16761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_xpt_done(np, cmd); 16771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 16781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 16811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Complete all active CCBs with error. 16821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Used on CHIP/SCSI RESET. 16831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sym_flush_busy_queue (struct sym_hcb *np, int cam_status) 16851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 16861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 16871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Move all active CCBs to the COMP queue 16881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and flush this queue. 16891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 16901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_que_splice(&np->busy_ccbq, &np->comp_ccbq); 16911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_que_init(&np->busy_ccbq); 16921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_flush_comp_queue(np, cam_status); 16931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 16941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 16951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 16961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Start chip. 16971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 16981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 'reason' means: 16991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 0: initialisation. 17001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1: SCSI BUS RESET delivered or received. 17011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 2: SCSI BUS MODE changed. 17021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 17035111eefa17615bdf17ca00ec2cdca16302c7697eMatthew Wilcoxvoid sym_start_up(struct Scsi_Host *shost, int reason) 17041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 17055111eefa17615bdf17ca00ec2cdca16302c7697eMatthew Wilcox struct sym_data *sym_data = shost_priv(shost); 17065111eefa17615bdf17ca00ec2cdca16302c7697eMatthew Wilcox struct pci_dev *pdev = sym_data->pdev; 17075111eefa17615bdf17ca00ec2cdca16302c7697eMatthew Wilcox struct sym_hcb *np = sym_data->ncb; 17081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 17091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 phys; 17101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 17121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Reset chip if asked, otherwise just clear fifos. 17131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 17141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (reason == 1) 17151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_soft_reset(np); 17161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 17171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_stest3, TE|CSF); 17181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTONB(np, nc_ctest3, CLF); 17191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 17221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Clear Start Queue 17231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 17241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds phys = np->squeue_ba; 17251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < MAX_QUEUE*2; i += 2) { 17261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->squeue[i] = cpu_to_scr(np->idletask_ba); 17271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->squeue[i+1] = cpu_to_scr(phys + (i+2)*4); 17281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->squeue[MAX_QUEUE*2-1] = cpu_to_scr(phys); 17301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 17321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Start at first entry. 17331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 17341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->squeueput = 0; 17351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 17371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Clear Done Queue 17381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 17391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds phys = np->dqueue_ba; 17401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0; i < MAX_QUEUE*2; i += 2) { 17411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->dqueue[i] = 0; 17421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->dqueue[i+1] = cpu_to_scr(phys + (i+2)*4); 17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 17441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->dqueue[MAX_QUEUE*2-1] = cpu_to_scr(phys); 17451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 17471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Start at first entry. 17481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 17491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->dqueueget = 0; 17501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 17521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Install patches in scripts. 17531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This also let point to first position the start 17541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and done queue pointers used from SCRIPTS. 17551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 17565111eefa17615bdf17ca00ec2cdca16302c7697eMatthew Wilcox np->fw_patch(shost); 17571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 17591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wakeup all pending jobs. 17601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 176153222b906903fd861dc24ebccfa07ee125941313Matthew Wilcox sym_flush_busy_queue(np, DID_RESET); 17621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 17641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Init chip. 17651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 17661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_istat, 0x00); /* Remove Reset, abort */ 176753222b906903fd861dc24ebccfa07ee125941313Matthew Wilcox INB(np, nc_mbox1); 17681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds udelay(2000); /* The 895 needs time for the bus mode to settle */ 17691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_scntl0, np->rv_scntl0 | 0xc0); 17711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* full arb., ena parity, par->ATN */ 17721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_scntl1, 0x00); /* odd parity, and remove CRST!! */ 17731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_selectclock(np, np->rv_scntl3); /* Select SCSI clock */ 17751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_scid , RRE|np->myaddr); /* Adapter SCSI address */ 17771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTW(np, nc_respid, 1ul<<np->myaddr); /* Id to respond to */ 17781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_istat , SIGP ); /* Signal Process */ 17791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_dmode , np->rv_dmode); /* Burst length, dma mode */ 17801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_ctest5, np->rv_ctest5); /* Large fifo + large burst */ 17811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_dcntl , NOCOM|np->rv_dcntl); /* Protect SFBR */ 17831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_ctest3, np->rv_ctest3); /* Write and invalidate */ 17841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_ctest4, np->rv_ctest4); /* Master parity checking */ 17851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Extended Sreq/Sack filtering not supported on the C10 */ 17871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->features & FE_C10) 17881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_stest2, np->rv_stest2); 17891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 17901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_stest2, EXT|np->rv_stest2); 17911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_stest3, TE); /* TolerANT enable */ 17931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_stime0, 0x0c); /* HTH disabled STO 0.25 sec */ 17941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 17961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For now, disable AIP generation on C1010-66. 17971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 17985111eefa17615bdf17ca00ec2cdca16302c7697eMatthew Wilcox if (pdev->device == PCI_DEVICE_ID_LSI_53C1010_66) 17991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_aipcntl1, DISAIP); 18001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 18021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * C10101 rev. 0 errata. 18031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Errant SGE's when in narrow. Write bits 4 & 5 of 18041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * STEST1 register to disable SGE. We probably should do 18051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that from SCRIPTS for each selection/reselection, but 18061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * I just don't want. :) 18071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 18085111eefa17615bdf17ca00ec2cdca16302c7697eMatthew Wilcox if (pdev->device == PCI_DEVICE_ID_LSI_53C1010_33 && 18095111eefa17615bdf17ca00ec2cdca16302c7697eMatthew Wilcox pdev->revision < 1) 18101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_stest1, INB(np, nc_stest1) | 0x30); 18111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 18131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * DEL 441 - 53C876 Rev 5 - Part Number 609-0392787/2788 - ITEM 2. 18141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Disable overlapped arbitration for some dual function devices, 18151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * regardless revision id (kind of post-chip-design feature. ;-)) 18161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 18175111eefa17615bdf17ca00ec2cdca16302c7697eMatthew Wilcox if (pdev->device == PCI_DEVICE_ID_NCR_53C875) 18181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_ctest0, (1<<5)); 18195111eefa17615bdf17ca00ec2cdca16302c7697eMatthew Wilcox else if (pdev->device == PCI_DEVICE_ID_NCR_53C896) 18201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->rv_ccntl0 |= DPR; 18211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 18231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Write CCNTL0/CCNTL1 for chips capable of 64 bit addressing 18241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and/or hardware phase mismatch, since only such chips 18251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * seem to support those IO registers. 18261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 18271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->features & (FE_DAC|FE_NOPM)) { 18281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_ccntl0, np->rv_ccntl0); 18291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_ccntl1, np->rv_ccntl1); 18301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if SYM_CONF_DMA_ADDRESSING_MODE == 2 18331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 18341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set up scratch C and DRS IO registers to map the 32 bit 18351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * DMA address range our data structures are located in. 18361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 18374d85b471593d03e141f9160a58574b9204363267Matthew Wilcox if (use_dac(np)) { 18381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->dmap_bah[0] = 0; /* ??? */ 18391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL(np, nc_scrx[0], np->dmap_bah[0]); 18401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL(np, nc_drs, np->dmap_bah[0]); 18411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 18431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 18451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If phase mismatch handled by scripts (895A/896/1010), 18461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * set PM jump addresses. 18471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 18481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->features & FE_NOPM) { 18491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL(np, nc_pmjad1, SCRIPTB_BA(np, pm_handle)); 18501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL(np, nc_pmjad2, SCRIPTB_BA(np, pm_handle)); 18511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 18541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Enable GPIO0 pin for writing if LED support from SCRIPTS. 18551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Also set GPIO5 and clear GPIO6 if hardware LED control. 18561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 18571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->features & FE_LED0) 18581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_gpcntl, INB(np, nc_gpcntl) & ~0x01); 18591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (np->features & FE_LEDC) 18601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_gpcntl, (INB(np, nc_gpcntl) & ~0x41) | 0x20); 18611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 18631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * enable ints 18641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 18651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTW(np, nc_sien , STO|HTH|MA|SGE|UDC|RST|PAR); 18661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_dien , MDPE|BF|SSI|SIR|IID); 18671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 18691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For 895/6 enable SBMC interrupt and save current SCSI bus mode. 18701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Try to eat the spurious SBMC interrupt that may occur when 18711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we reset the chip but not the SCSI BUS (at initialization). 18721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 18731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->features & (FE_ULTRA2|FE_ULTRA3)) { 18741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTONW(np, nc_sien, SBMC); 18751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (reason == 0) { 187653222b906903fd861dc24ebccfa07ee125941313Matthew Wilcox INB(np, nc_mbox1); 18771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds mdelay(100); 18781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds INW(np, nc_sist); 18791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->scsi_mode = INB(np, nc_stest4) & SMODE; 18811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 18821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 18841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Fill in target structure. 18851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Reinitialize usrsync. 18861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Reinitialize usrwide. 18871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Prepare sync negotiation according to actual SCSI bus mode. 18881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 18891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i=0;i<SYM_CONF_MAX_TARGET;i++) { 18901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_tcb *tp = &np->target[i]; 18911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 18921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->to_reset = 0; 18931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->head.sval = 0; 18941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->head.wval = np->rv_scntl3; 18951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->head.uval = 0; 1896410604d25faddb1b4f0f9667b7452c06cc06cea1Aaro Koskinen if (tp->lun0p) 1897410604d25faddb1b4f0f9667b7452c06cc06cea1Aaro Koskinen tp->lun0p->to_clear = 0; 1898410604d25faddb1b4f0f9667b7452c06cc06cea1Aaro Koskinen if (tp->lunmp) { 1899410604d25faddb1b4f0f9667b7452c06cc06cea1Aaro Koskinen int ln; 1900410604d25faddb1b4f0f9667b7452c06cc06cea1Aaro Koskinen 1901410604d25faddb1b4f0f9667b7452c06cc06cea1Aaro Koskinen for (ln = 1; ln < SYM_CONF_MAX_LUN; ln++) 1902410604d25faddb1b4f0f9667b7452c06cc06cea1Aaro Koskinen if (tp->lunmp[ln]) 1903410604d25faddb1b4f0f9667b7452c06cc06cea1Aaro Koskinen tp->lunmp[ln]->to_clear = 0; 1904410604d25faddb1b4f0f9667b7452c06cc06cea1Aaro Koskinen } 19051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 19081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Download SCSI SCRIPTS to on-chip RAM if present, 19091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and start script processor. 19101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We do the download preferently from the CPU. 19111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For platforms that may not support PCI memory mapping, 19121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we use simple SCRIPTS that performs MEMORY MOVEs. 19131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 19141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds phys = SCRIPTA_BA(np, init); 19151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->ram_ba) { 19161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sym_verbose >= 2) 19171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf("%s: Downloading SCSI SCRIPTS.\n", sym_name(np)); 19181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy_toio(np->s.ramaddr, np->scripta0, np->scripta_sz); 19198637baa3609afff9fe4c65ad4c64d72484c699fcMatthew Wilcox if (np->features & FE_RAM8K) { 19201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy_toio(np->s.ramaddr + 4096, np->scriptb0, np->scriptb_sz); 19211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds phys = scr_to_cpu(np->scr_ram_seg); 19221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL(np, nc_mmws, phys); 19231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL(np, nc_mmrs, phys); 19241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL(np, nc_sfs, phys); 19251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds phys = SCRIPTB_BA(np, start64); 19261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->istat_sem = 0; 19301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL(np, nc_dsa, np->hcb_ba); 19321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL_DSP(np, phys); 19331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 19351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Notify the XPT about the RESET condition. 19361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 19371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (reason != 0) 19381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_xpt_async_bus_reset(np); 19391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 19401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 19421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Switch trans mode for current job and its target. 19431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 19441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sym_settrans(struct sym_hcb *np, int target, u_char opts, u_char ofs, 19451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char per, u_char wide, u_char div, u_char fak) 19461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 19471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SYM_QUEHEAD *qp; 19481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char sval, wval, uval; 19491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_tcb *tp = &np->target[target]; 19501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds assert(target == (INB(np, nc_sdid) & 0x0f)); 19521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sval = tp->head.sval; 19541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wval = tp->head.wval; 19551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uval = tp->head.uval; 19561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 19581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf("XXXX sval=%x wval=%x uval=%x (%x)\n", 19591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sval, wval, uval, np->rv_scntl3); 19601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 19611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 19621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set the offset. 19631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 19641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(np->features & FE_C10)) 19651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sval = (sval & ~0x1f) | ofs; 19661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 19671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sval = (sval & ~0x3f) | ofs; 19681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 19701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set the sync divisor and extra clock factor. 19711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 19721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ofs != 0) { 19731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wval = (wval & ~0x70) | ((div+1) << 4); 19741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(np->features & FE_C10)) 19751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sval = (sval & ~0xe0) | (fak << 5); 19761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 19771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uval = uval & ~(XCLKH_ST|XCLKH_DT|XCLKS_ST|XCLKS_DT); 19781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fak >= 1) uval |= (XCLKH_ST|XCLKH_DT); 19791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fak >= 2) uval |= (XCLKS_ST|XCLKS_DT); 19801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 19841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set the bus width. 19851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 19861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wval = wval & ~EWS; 19871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (wide != 0) 19881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wval |= EWS; 19891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 19911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set misc. ultra enable bits. 19921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 19931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->features & FE_C10) { 19941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uval = uval & ~(U3EN|AIPCKEN); 19951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (opts) { 19961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds assert(np->features & FE_U3EN); 19971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uval |= U3EN; 19981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 19991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 20001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wval = wval & ~ULTRA; 20011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (per <= 12) wval |= ULTRA; 20021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 20051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Stop there if sync parameters are unchanged. 20061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 20071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tp->head.sval == sval && 20081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->head.wval == wval && 20091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->head.uval == uval) 20101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 20111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->head.sval = sval; 20121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->head.wval = wval; 20131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->head.uval = uval; 20141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 20161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Disable extended Sreq/Sack filtering if per < 50. 20171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Not supported on the C1010. 20181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 20191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (per < 50 && !(np->features & FE_C10)) 20201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTOFFB(np, nc_stest2, EXT); 20211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 20231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * set actual value and sync_status 20241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 20251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_sxfer, tp->head.sval); 20261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_scntl3, tp->head.wval); 20271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->features & FE_C10) { 20291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_scntl4, tp->head.uval); 20301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 20331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * patch ALL busy ccbs of this target. 20341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 20351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) { 20361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_ccb *cp; 20371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); 20381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp->target != target) 20391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 20401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->phys.select.sel_scntl3 = tp->head.wval; 20411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->phys.select.sel_sxfer = tp->head.sval; 20421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->features & FE_C10) { 20431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->phys.select.sel_scntl4 = tp->head.uval; 20441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 20461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 20471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2048058bb82c5628c88af802c19e2b56ae43551552d5Tony Battersbystatic void sym_announce_transfer_rate(struct sym_tcb *tp) 2049058bb82c5628c88af802c19e2b56ae43551552d5Tony Battersby{ 2050058bb82c5628c88af802c19e2b56ae43551552d5Tony Battersby struct scsi_target *starget = tp->starget; 2051058bb82c5628c88af802c19e2b56ae43551552d5Tony Battersby 2052058bb82c5628c88af802c19e2b56ae43551552d5Tony Battersby if (tp->tprint.period != spi_period(starget) || 2053058bb82c5628c88af802c19e2b56ae43551552d5Tony Battersby tp->tprint.offset != spi_offset(starget) || 2054058bb82c5628c88af802c19e2b56ae43551552d5Tony Battersby tp->tprint.width != spi_width(starget) || 2055058bb82c5628c88af802c19e2b56ae43551552d5Tony Battersby tp->tprint.iu != spi_iu(starget) || 2056058bb82c5628c88af802c19e2b56ae43551552d5Tony Battersby tp->tprint.dt != spi_dt(starget) || 2057058bb82c5628c88af802c19e2b56ae43551552d5Tony Battersby tp->tprint.qas != spi_qas(starget) || 2058058bb82c5628c88af802c19e2b56ae43551552d5Tony Battersby !tp->tprint.check_nego) { 2059058bb82c5628c88af802c19e2b56ae43551552d5Tony Battersby tp->tprint.period = spi_period(starget); 2060058bb82c5628c88af802c19e2b56ae43551552d5Tony Battersby tp->tprint.offset = spi_offset(starget); 2061058bb82c5628c88af802c19e2b56ae43551552d5Tony Battersby tp->tprint.width = spi_width(starget); 2062058bb82c5628c88af802c19e2b56ae43551552d5Tony Battersby tp->tprint.iu = spi_iu(starget); 2063058bb82c5628c88af802c19e2b56ae43551552d5Tony Battersby tp->tprint.dt = spi_dt(starget); 2064058bb82c5628c88af802c19e2b56ae43551552d5Tony Battersby tp->tprint.qas = spi_qas(starget); 2065058bb82c5628c88af802c19e2b56ae43551552d5Tony Battersby tp->tprint.check_nego = 1; 2066058bb82c5628c88af802c19e2b56ae43551552d5Tony Battersby 2067058bb82c5628c88af802c19e2b56ae43551552d5Tony Battersby spi_display_xfer_agreement(starget); 2068058bb82c5628c88af802c19e2b56ae43551552d5Tony Battersby } 2069058bb82c5628c88af802c19e2b56ae43551552d5Tony Battersby} 2070058bb82c5628c88af802c19e2b56ae43551552d5Tony Battersby 20711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 20721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We received a WDTR. 20731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Let everything be aware of the changes. 20741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 20751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sym_setwide(struct sym_hcb *np, int target, u_char wide) 20761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 20771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_tcb *tp = &np->target[target]; 207853222b906903fd861dc24ebccfa07ee125941313Matthew Wilcox struct scsi_target *starget = tp->starget; 20791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_settrans(np, target, 0, 0, 0, wide, 0, 0); 20811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 208249799fee82b4f78c45b1926be24e45b5cf667083Aaro Koskinen if (wide) 208349799fee82b4f78c45b1926be24e45b5cf667083Aaro Koskinen tp->tgoal.renego = NS_WIDE; 208449799fee82b4f78c45b1926be24e45b5cf667083Aaro Koskinen else 208549799fee82b4f78c45b1926be24e45b5cf667083Aaro Koskinen tp->tgoal.renego = 0; 208649799fee82b4f78c45b1926be24e45b5cf667083Aaro Koskinen tp->tgoal.check_nego = 0; 20871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->tgoal.width = wide; 20881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spi_offset(starget) = 0; 20891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spi_period(starget) = 0; 20901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spi_width(starget) = wide; 20911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spi_iu(starget) = 0; 20921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spi_dt(starget) = 0; 20931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spi_qas(starget) = 0; 20941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sym_verbose >= 3) 2096058bb82c5628c88af802c19e2b56ae43551552d5Tony Battersby sym_announce_transfer_rate(tp); 20971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 20981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 20991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We received a SDTR. 21011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Let everything be aware of the changes. 21021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 21031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 21041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssym_setsync(struct sym_hcb *np, int target, 21051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char ofs, u_char per, u_char div, u_char fak) 21061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 21071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_tcb *tp = &np->target[target]; 210853222b906903fd861dc24ebccfa07ee125941313Matthew Wilcox struct scsi_target *starget = tp->starget; 21091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char wide = (tp->head.wval & EWS) ? BUS_16_BIT : BUS_8_BIT; 21101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_settrans(np, target, 0, ofs, per, wide, div, fak); 21121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 211349799fee82b4f78c45b1926be24e45b5cf667083Aaro Koskinen if (wide) 211449799fee82b4f78c45b1926be24e45b5cf667083Aaro Koskinen tp->tgoal.renego = NS_WIDE; 211549799fee82b4f78c45b1926be24e45b5cf667083Aaro Koskinen else if (ofs) 211649799fee82b4f78c45b1926be24e45b5cf667083Aaro Koskinen tp->tgoal.renego = NS_SYNC; 211749799fee82b4f78c45b1926be24e45b5cf667083Aaro Koskinen else 211849799fee82b4f78c45b1926be24e45b5cf667083Aaro Koskinen tp->tgoal.renego = 0; 21191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spi_period(starget) = per; 21201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spi_offset(starget) = ofs; 21211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spi_iu(starget) = spi_dt(starget) = spi_qas(starget) = 0; 21221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!tp->tgoal.dt && !tp->tgoal.iu && !tp->tgoal.qas) { 21241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->tgoal.period = per; 21251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->tgoal.offset = ofs; 21261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->tgoal.check_nego = 0; 21271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 21281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2129058bb82c5628c88af802c19e2b56ae43551552d5Tony Battersby sym_announce_transfer_rate(tp); 21301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 21311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We received a PPR. 21341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Let everything be aware of the changes. 21351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 21361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 21371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssym_setpprot(struct sym_hcb *np, int target, u_char opts, u_char ofs, 21381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char per, u_char wide, u_char div, u_char fak) 21391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 21401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_tcb *tp = &np->target[target]; 214153222b906903fd861dc24ebccfa07ee125941313Matthew Wilcox struct scsi_target *starget = tp->starget; 21421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_settrans(np, target, opts, ofs, per, wide, div, fak); 21441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 214549799fee82b4f78c45b1926be24e45b5cf667083Aaro Koskinen if (wide || ofs) 214649799fee82b4f78c45b1926be24e45b5cf667083Aaro Koskinen tp->tgoal.renego = NS_PPR; 214749799fee82b4f78c45b1926be24e45b5cf667083Aaro Koskinen else 214849799fee82b4f78c45b1926be24e45b5cf667083Aaro Koskinen tp->tgoal.renego = 0; 21491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spi_width(starget) = tp->tgoal.width = wide; 21501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spi_period(starget) = tp->tgoal.period = per; 21511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spi_offset(starget) = tp->tgoal.offset = ofs; 21521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spi_iu(starget) = tp->tgoal.iu = !!(opts & PPR_OPT_IU); 21531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spi_dt(starget) = tp->tgoal.dt = !!(opts & PPR_OPT_DT); 21541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spi_qas(starget) = tp->tgoal.qas = !!(opts & PPR_OPT_QAS); 21551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->tgoal.check_nego = 0; 21561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2157058bb82c5628c88af802c19e2b56ae43551552d5Tony Battersby sym_announce_transfer_rate(tp); 21581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 21591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * generic recovery from scsi interrupt 21621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 21631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The doc says that when the chip gets an SCSI interrupt, 21641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it tries to stop in an orderly fashion, by completing 21651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * an instruction fetch that had started or by flushing 21661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the DMA fifo for a write to memory that was executing. 21671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Such a fashion is not enough to know if the instruction 21681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that was just before the current DSP value has been 21691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * executed or not. 21701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 21711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * There are some small SCRIPTS sections that deal with 21721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the start queue and the done queue that may break any 21731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * assomption from the C code if we are interrupted 21741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * inside, so we reset if this happens. Btw, since these 21751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SCRIPTS sections are executed while the SCRIPTS hasn't 21761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * started SCSI operations, it is very unlikely to happen. 21771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 21781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * All the driver data structures are supposed to be 21791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * allocated from the same 4 GB memory window, so there 21801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is a 1 to 1 relationship between DSA and driver data 21811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * structures. Since we are careful :) to invalidate the 21821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * DSA when we complete a command or when the SCRIPTS 21831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pushes a DSA into a queue, we can trust it when it 21841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * points to a CCB. 21851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 21861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sym_recover_scsi_int (struct sym_hcb *np, u_char hsts) 21871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 21881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 dsp = INL(np, nc_dsp); 21891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 dsa = INL(np, nc_dsa); 21901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_ccb *cp = sym_ccb_from_dsa(np, dsa); 21911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 21931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we haven't been interrupted inside the SCRIPTS 21941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * critical pathes, we can safely restart the SCRIPTS 21951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and trust the DSA value if it matches a CCB. 21961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 21971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((!(dsp > SCRIPTA_BA(np, getjob_begin) && 21981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dsp < SCRIPTA_BA(np, getjob_end) + 1)) && 21991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (!(dsp > SCRIPTA_BA(np, ungetjob) && 22001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dsp < SCRIPTA_BA(np, reselect) + 1)) && 22011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (!(dsp > SCRIPTB_BA(np, sel_for_abort) && 22021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dsp < SCRIPTB_BA(np, sel_for_abort_1) + 1)) && 22031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (!(dsp > SCRIPTA_BA(np, done) && 22041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dsp < SCRIPTA_BA(np, done_end) + 1))) { 22051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_ctest3, np->rv_ctest3 | CLF); /* clear dma fifo */ 22061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_stest3, TE|CSF); /* clear scsi fifo */ 22071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 22081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we have a CCB, let the SCRIPTS call us back for 22091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the handling of the error with SCRATCHA filled with 22101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * STARTPOS. This way, we will be able to freeze the 22111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * device queue and requeue awaiting IOs. 22121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 22131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp) { 22141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->host_status = hsts; 22151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL_DSP(np, SCRIPTA_BA(np, complete_error)); 22161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 22181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Otherwise just restart the SCRIPTS. 22191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 22201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 22211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL(np, nc_dsa, 0xffffff); 22221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL_DSP(np, SCRIPTA_BA(np, start)); 22231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 22251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 22261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto reset_all; 22271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 22291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreset_all: 22311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_start_reset(np); 22321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 22331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 22351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * chip exception handler for selection timeout 22361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 22371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sym_int_sto (struct sym_hcb *np) 22381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 22391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 dsp = INL(np, nc_dsp); 22401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (DEBUG_FLAGS & DEBUG_TINY) printf ("T"); 22421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dsp == SCRIPTA_BA(np, wf_sel_done) + 8) 22441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_recover_scsi_int(np, HS_SEL_TIMEOUT); 22451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 22461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_start_reset(np); 22471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 22481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 22501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * chip exception handler for unexpected disconnect 22511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 22521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sym_int_udc (struct sym_hcb *np) 22531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 22541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf ("%s: unexpected disconnect\n", sym_name(np)); 22551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_recover_scsi_int(np, HS_UNEXPECTED); 22561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 22571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 22591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * chip exception handler for SCSI bus mode change 22601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 22611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * spi2-r12 11.2.3 says a transceiver mode change must 22621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * generate a reset event and a device that detects a reset 22631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * event shall initiate a hard reset. It says also that a 22641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * device that detects a mode change shall set data transfer 22651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * mode to eight bit asynchronous, etc... 22661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * So, just reinitializing all except chip should be enough. 22671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 22685111eefa17615bdf17ca00ec2cdca16302c7697eMatthew Wilcoxstatic void sym_int_sbmc(struct Scsi_Host *shost) 22691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 22705111eefa17615bdf17ca00ec2cdca16302c7697eMatthew Wilcox struct sym_hcb *np = sym_get_hcb(shost); 22711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char scsi_mode = INB(np, nc_stest4) & SMODE; 22721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 22741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Notify user. 22751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 22761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf("%s: SCSI BUS mode change from %s to %s.\n", sym_name(np), 22771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_scsi_bus_mode(np->scsi_mode), sym_scsi_bus_mode(scsi_mode)); 22781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 22801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Should suspend command processing for a few seconds and 22811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * reinitialize all except the chip. 22821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 22835111eefa17615bdf17ca00ec2cdca16302c7697eMatthew Wilcox sym_start_up(shost, 2); 22841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 22851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 22861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 22871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * chip exception handler for SCSI parity error. 22881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 22891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * When the chip detects a SCSI parity error and is 22901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * currently executing a (CH)MOV instruction, it does 22911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * not interrupt immediately, but tries to finish the 22921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * transfer of the current scatter entry before 22931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * interrupting. The following situations may occur: 22941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 22951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - The complete scatter entry has been transferred 22961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * without the device having changed phase. 22971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The chip will then interrupt with the DSP pointing 22981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to the instruction that follows the MOV. 22991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 23001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - A phase mismatch occurs before the MOV finished 23011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and phase errors are to be handled by the C code. 23021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The chip will then interrupt with both PAR and MA 23031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * conditions set. 23041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 23051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - A phase mismatch occurs before the MOV finished and 23061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * phase errors are to be handled by SCRIPTS. 23071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The chip will load the DSP with the phase mismatch 23081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * JUMP address and interrupt the host processor. 23091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 23101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sym_int_par (struct sym_hcb *np, u_short sist) 23111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 23121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char hsts = INB(np, HS_PRT); 23131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 dsp = INL(np, nc_dsp); 23141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 dbc = INL(np, nc_dbc); 23151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 dsa = INL(np, nc_dsa); 23161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char sbcl = INB(np, nc_sbcl); 23171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char cmd = dbc >> 24; 23181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int phase = cmd & 7; 23191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_ccb *cp = sym_ccb_from_dsa(np, dsa); 23201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 232175be63bcf73ebdd1fdc1d49f6bf2d1326a1ba7deJohn Stoffel if (printk_ratelimit()) 232275be63bcf73ebdd1fdc1d49f6bf2d1326a1ba7deJohn Stoffel printf("%s: SCSI parity error detected: SCR1=%d DBC=%x SBCL=%x\n", 232375be63bcf73ebdd1fdc1d49f6bf2d1326a1ba7deJohn Stoffel sym_name(np), hsts, dbc, sbcl); 23241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 23261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Check that the chip is connected to the SCSI BUS. 23271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 23281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(INB(np, nc_scntl1) & ISCON)) { 23291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_recover_scsi_int(np, HS_UNEXPECTED); 23301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 23311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 23341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the nexus is not clearly identified, reset the bus. 23351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We will try to do better later. 23361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 23371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!cp) 23381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto reset_all; 23391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 23411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Check instruction was a MOV, direction was INPUT and 23421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ATN is asserted. 23431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 23441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((cmd & 0xc0) || !(phase & 1) || !(sbcl & 0x8)) 23451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto reset_all; 23461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 23481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Keep track of the parity error. 23491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 23501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTONB(np, HF_PRT, HF_EXT_ERR); 23511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->xerr_status |= XE_PARITY_ERR; 23521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 23541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Prepare the message to send to the device. 23551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 23561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->msgout[0] = (phase == 7) ? M_PARITY : M_ID_ERROR; 23571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 23591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the old phase was DATA IN phase, we have to deal with 23601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the 3 situations described above. 23611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For other input phases (MSG IN and STATUS), the device 23621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * must resend the whole thing that failed parity checking 23631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * or signal error. So, jumping to dispatcher should be OK. 23641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 23651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (phase == 1 || phase == 5) { 23661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Phase mismatch handled by SCRIPTS */ 23671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dsp == SCRIPTB_BA(np, pm_handle)) 23681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL_DSP(np, dsp); 23691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Phase mismatch handled by the C code */ 23701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (sist & MA) 23711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_int_ma (np); 23721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* No phase mismatch occurred */ 23731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 23741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_set_script_dp (np, cp, dsp); 23751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL_DSP(np, SCRIPTA_BA(np, dispatch)); 23761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 23781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (phase == 7) /* We definitely cannot handle parity errors */ 23791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 1 /* in message-in phase due to the relection */ 23801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto reset_all; /* path and various message anticipations. */ 23811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 23821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL_DSP(np, SCRIPTA_BA(np, clrack)); 23831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 23841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 23851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL_DSP(np, SCRIPTA_BA(np, dispatch)); 23861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 23871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreset_all: 23891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_start_reset(np); 23901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 23911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 23921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 23931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 23941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * chip exception handler for phase errors. 23951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 23961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We have to construct a new transfer descriptor, 23971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to transfer the rest of the current block. 23981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 23991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sym_int_ma (struct sym_hcb *np) 24001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 24011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 dbc; 24021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 rest; 24031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 dsp; 24041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 dsa; 24051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 nxtdsp; 24061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 *vdsp; 24071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 oadr, olen; 24081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 *tblp; 24091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 newcmd; 24101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int delta; 24111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char cmd; 24121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char hflags, hflags0; 24131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_pmc *pm; 24141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_ccb *cp; 24151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dsp = INL(np, nc_dsp); 24171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dbc = INL(np, nc_dbc); 24181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dsa = INL(np, nc_dsa); 24191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd = dbc >> 24; 24211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rest = dbc & 0xffffff; 24221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds delta = 0; 24231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 24251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * locate matching cp if any. 24261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 24271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp = sym_ccb_from_dsa(np, dsa); 24281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 24301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Donnot take into account dma fifo and various buffers in 24311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * INPUT phase since the chip flushes everything before 24321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * raising the MA interrupt for interrupted INPUT phases. 24331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For DATA IN phase, we will check for the SWIDE later. 24341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 24351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((cmd & 7) != 1 && (cmd & 7) != 5) { 24361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char ss0, ss2; 24371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->features & FE_DFBC) 24391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds delta = INW(np, nc_dfbc); 24401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 24411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 dfifo; 24421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 24441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Read DFIFO, CTEST[4-6] using 1 PCI bus ownership. 24451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 24461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dfifo = INL(np, nc_dfifo); 24471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 24491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Calculate remaining bytes in DMA fifo. 24501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (CTEST5 = dfifo >> 16) 24511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 24521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dfifo & (DFS << 16)) 24531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds delta = ((((dfifo >> 8) & 0x300) | 24541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (dfifo & 0xff)) - rest) & 0x3ff; 24551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 24561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds delta = ((dfifo & 0xff) - rest) & 0x7f; 24571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 246025985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * The data in the dma fifo has not been transferred to 24611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the target -> add the amount to the rest 24621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and clear the data. 24631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Check the sstat2 register in case of wide transfer. 24641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 24651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds rest += delta; 24661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ss0 = INB(np, nc_sstat0); 24671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ss0 & OLF) rest++; 24681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(np->features & FE_C10)) 24691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ss0 & ORF) rest++; 24701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp && (cp->phys.select.sel_scntl3 & EWS)) { 24711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ss2 = INB(np, nc_sstat2); 24721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ss2 & OLF1) rest++; 24731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(np->features & FE_C10)) 24741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ss2 & ORF1) rest++; 24751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 24781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Clear fifos. 24791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 24801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_ctest3, np->rv_ctest3 | CLF); /* dma fifo */ 24811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_stest3, TE|CSF); /* scsi fifo */ 24821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 24831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 24851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * log the information 24861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 24871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_PHASE)) 24881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf ("P%x%x RL=%d D=%d ", cmd&7, INB(np, nc_sbcl)&7, 24891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned) rest, (unsigned) delta); 24901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 24911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 24921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * try to find the interrupted script command, 24931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and the address at which to continue. 24941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 24951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vdsp = NULL; 24961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nxtdsp = 0; 24971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dsp > np->scripta_ba && 24981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dsp <= np->scripta_ba + np->scripta_sz) { 24991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vdsp = (u32 *)((char*)np->scripta0 + (dsp-np->scripta_ba-8)); 25001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nxtdsp = dsp; 25011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (dsp > np->scriptb_ba && 25031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dsp <= np->scriptb_ba + np->scriptb_sz) { 25041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds vdsp = (u32 *)((char*)np->scriptb0 + (dsp-np->scriptb_ba-8)); 25051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nxtdsp = dsp; 25061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 25091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * log the information 25101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 25111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (DEBUG_FLAGS & DEBUG_PHASE) { 25121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf ("\nCP=%p DSP=%x NXT=%x VDSP=%p CMD=%x ", 25131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp, (unsigned)dsp, (unsigned)nxtdsp, vdsp, cmd); 25141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!vdsp) { 25171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf ("%s: interrupted SCRIPT address not found.\n", 25181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_name (np)); 25191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto reset_all; 25201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!cp) { 25231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf ("%s: SCSI phase error fixup: CCB already dequeued.\n", 25241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_name (np)); 25251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto reset_all; 25261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 25291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * get old startaddress and old length. 25301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 25311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds oadr = scr_to_cpu(vdsp[1]); 25321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cmd & 0x10) { /* Table indirect */ 25341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tblp = (u32 *) ((char*) &cp->phys + oadr); 25351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds olen = scr_to_cpu(tblp[0]); 25361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds oadr = scr_to_cpu(tblp[1]); 25371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 25381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tblp = (u32 *) 0; 25391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds olen = scr_to_cpu(vdsp[0]) & 0xffffff; 25401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (DEBUG_FLAGS & DEBUG_PHASE) { 25431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf ("OCMD=%x\nTBLP=%p OLEN=%x OADR=%x\n", 25441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned) (scr_to_cpu(vdsp[0]) >> 24), 25451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tblp, 25461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned) olen, 25471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned) oadr); 25481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 25511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * check cmd against assumed interrupted script command. 25521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If dt data phase, the MOVE instruction hasn't bit 4 of 25531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the phase. 25541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 25551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (((cmd & 2) ? cmd : (cmd & ~4)) != (scr_to_cpu(vdsp[0]) >> 24)) { 25561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_print_addr(cp->cmd, 25571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "internal error: cmd=%02x != %02x=(vdsp[0] >> 24)\n", 25581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd, scr_to_cpu(vdsp[0]) >> 24); 25591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto reset_all; 25611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 25641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if old phase not dataphase, leave here. 25651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 25661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cmd & 2) { 25671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_print_addr(cp->cmd, 25681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "phase change %x-%x %d@%08x resid=%d.\n", 25691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd&7, INB(np, nc_sbcl)&7, (unsigned)olen, 25701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned)oadr, (unsigned)rest); 25711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto unexpected_phase; 25721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 25751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Choose the correct PM save area. 25761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 25771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Look at the PM_SAVE SCRIPT if you want to understand 25781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this stuff. The equivalent code is implemented in 25791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SCRIPTS for the 895A, 896 and 1010 that are able to 25801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * handle PM from the SCRIPTS processor. 25811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 25821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hflags0 = INB(np, HF_PRT); 25831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hflags = hflags0; 25841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (hflags & (HF_IN_PM0 | HF_IN_PM1 | HF_DP_SAVED)) { 25861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (hflags & HF_IN_PM0) 25871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nxtdsp = scr_to_cpu(cp->phys.pm0.ret); 25881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (hflags & HF_IN_PM1) 25891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nxtdsp = scr_to_cpu(cp->phys.pm1.ret); 25901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (hflags & HF_DP_SAVED) 25921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hflags ^= HF_ACT_PM; 25931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 25951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(hflags & HF_ACT_PM)) { 25961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pm = &cp->phys.pm0; 25971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newcmd = SCRIPTA_BA(np, pm0_data); 25981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 25991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 26001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pm = &cp->phys.pm1; 26011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newcmd = SCRIPTA_BA(np, pm1_data); 26021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 26031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hflags &= ~(HF_IN_PM0 | HF_IN_PM1 | HF_DP_SAVED); 26051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (hflags != hflags0) 26061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, HF_PRT, hflags); 26071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 26091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * fillin the phase mismatch context 26101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 26111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pm->sg.addr = cpu_to_scr(oadr + olen - rest); 26121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pm->sg.size = cpu_to_scr(rest); 26131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pm->ret = cpu_to_scr(nxtdsp); 26141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 26161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we have a SWIDE, 26171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - prepare the address to write the SWIDE from SCRIPTS, 26181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - compute the SCRIPTS address to restart from, 26191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - move current data pointer context by one byte. 26201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 26211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nxtdsp = SCRIPTA_BA(np, dispatch); 26221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((cmd & 7) == 1 && cp && (cp->phys.select.sel_scntl3 & EWS) && 26231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (INB(np, nc_scntl2) & WSR)) { 26241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 tmp; 26251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 26271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set up the table indirect for the MOVE 26281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of the residual byte and adjust the data 26291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pointer context. 26301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 26311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = scr_to_cpu(pm->sg.addr); 26321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->phys.wresid.addr = cpu_to_scr(tmp); 26331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pm->sg.addr = cpu_to_scr(tmp + 1); 26341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = scr_to_cpu(pm->sg.size); 26351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->phys.wresid.size = cpu_to_scr((tmp&0xff000000) | 1); 26361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pm->sg.size = cpu_to_scr(tmp - 1); 26371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 26391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If only the residual byte is to be moved, 26401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * no PM context is needed. 26411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 26421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((tmp&0xffffff) == 1) 26431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds newcmd = pm->ret; 26441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 26461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Prepare the address of SCRIPTS that will 26471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * move the residual byte to memory. 26481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 26491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nxtdsp = SCRIPTB_BA(np, wsr_ma_helper); 26501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 26511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (DEBUG_FLAGS & DEBUG_PHASE) { 26531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_print_addr(cp->cmd, "PM %x %x %x / %x %x %x.\n", 26541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hflags0, hflags, newcmd, 26551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned)scr_to_cpu(pm->sg.addr), 26561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned)scr_to_cpu(pm->sg.size), 26571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned)scr_to_cpu(pm->ret)); 26581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 26591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 26611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Restart the SCRIPTS processor. 26621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 26631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_set_script_dp (np, cp, newcmd); 26641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL_DSP(np, nxtdsp); 26651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 26661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 26681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Unexpected phase changes that occurs when the current phase 26691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is not a DATA IN or DATA OUT phase are due to error conditions. 26701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Such event may only happen when the SCRIPTS is using a 26711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * multibyte SCSI MOVE. 26721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 26731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Phase change Some possible cause 26741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 26751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * COMMAND --> MSG IN SCSI parity error detected by target. 26761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * COMMAND --> STATUS Bad command or refused by target. 26771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MSG OUT --> MSG IN Message rejected by target. 26781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MSG OUT --> COMMAND Bogus target that discards extended 26791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * negotiation messages. 26801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 26811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The code below does not care of the new phase and so 26821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * trusts the target. Why to annoy it ? 26831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the interrupted phase is COMMAND phase, we restart at 26841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dispatcher. 26851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If a target does not get all the messages after selection, 26861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the code assumes blindly that the target discards extended 26871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * messages and clears the negotiation status. 26881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the target does not want all our response to negotiation, 26891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we force a SIR_NEGO_PROTO interrupt (it is a hack that avoids 26901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bloat for such a should_not_happen situation). 26911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * In all other situation, we reset the BUS. 2692af901ca181d92aac3a7dc265144a9081a86d8f39André Goddard Rosa * Are these assumptions reasonable ? (Wait and see ...) 26931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 26941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsunexpected_phase: 26951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dsp -= 8; 26961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nxtdsp = 0; 26971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cmd & 7) { 26991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 2: /* COMMAND phase */ 27001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nxtdsp = SCRIPTA_BA(np, dispatch); 27011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 27021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 27031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 3: /* STATUS phase */ 27041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nxtdsp = SCRIPTA_BA(np, dispatch); 27051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 27061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 27071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 6: /* MSG OUT phase */ 27081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 27091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the device may want to use untagged when we want 27101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * tagged, we prepare an IDENTIFY without disc. granted, 27111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * since we will not be able to handle reselect. 27121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Otherwise, we just don't care. 27131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 27141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dsp == SCRIPTA_BA(np, send_ident)) { 27151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp->tag != NO_TAG && olen - rest <= 3) { 27161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->host_status = HS_BUSY; 27171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->msgout[0] = IDENTIFY(0, cp->lun); 27181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nxtdsp = SCRIPTB_BA(np, ident_break_atn); 27191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 27201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 27211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nxtdsp = SCRIPTB_BA(np, ident_break); 27221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 27231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (dsp == SCRIPTB_BA(np, send_wdtr) || 27241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dsp == SCRIPTB_BA(np, send_sdtr) || 27251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dsp == SCRIPTB_BA(np, send_ppr)) { 27261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nxtdsp = SCRIPTB_BA(np, nego_bad_phase); 27271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dsp == SCRIPTB_BA(np, send_ppr)) { 27281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scsi_device *dev = cp->cmd->device; 27291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->ppr = 0; 27301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 27311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 27321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 27331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 27341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case 7: /* MSG IN phase */ 27351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds nxtdsp = SCRIPTA_BA(np, clrack); 27361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 27371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 27381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 27391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (nxtdsp) { 27411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL_DSP(np, nxtdsp); 27421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 27431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 27441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreset_all: 27461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_start_reset(np); 27471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 27481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 27491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 27501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * chip interrupt handler 27511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 27521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * In normal situations, interrupt conditions occur one at 27531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a time. But when something bad happens on the SCSI BUS, 27541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the chip may raise several interrupt flags before 27551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * stopping and interrupting the CPU. The additionnal 27561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * interrupt flags are stacked in some extra registers 27571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * after the SIP and/or DIP flag has been raised in the 27581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ISTAT. After the CPU has read the interrupt condition 27591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * flag from SIST or DSTAT, the chip unstacks the other 27601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * interrupt flags and sets the corresponding bits in 27611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SIST or DSTAT. Since the chip starts stacking once the 27621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SIP or DIP flag is set, there is a small window of time 27631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * where the stacking does not occur. 27641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 27651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Typically, multiple interrupt conditions may happen in 27661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the following situations: 27671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 27681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - SCSI parity error + Phase mismatch (PAR|MA) 27691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * When an parity error is detected in input phase 27701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and the device switches to msg-in phase inside a 27711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * block MOV. 27721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - SCSI parity error + Unexpected disconnect (PAR|UDC) 27731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * When a stupid device does not want to handle the 27741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * recovery of an SCSI parity error. 27751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - Some combinations of STO, PAR, UDC, ... 27761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * When using non compliant SCSI stuff, when user is 27771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * doing non compliant hot tampering on the BUS, when 27781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * something really bad happens to a device, etc ... 27791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 27801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The heuristic suggested by SYMBIOS to handle 27811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * multiple interrupts is to try unstacking all 27821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * interrupts conditions and to handle them on some 27831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * priority based on error severity. 27841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This will work when the unstacking has been 27851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * successful, but we cannot be 100 % sure of that, 27861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * since the CPU may have been faster to unstack than 27871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the chip is able to stack. Hmmm ... But it seems that 27881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * such a situation is very unlikely to happen. 27891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 27901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If this happen, for example STO caught by the CPU 27911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * then UDC happenning before the CPU have restarted 27921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the SCRIPTS, the driver may wrongly complete the 27931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * same command on UDC, since the SCRIPTS didn't restart 27941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and the DSA still points to the same command. 27951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We avoid this situation by setting the DSA to an 27961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * invalid value when the CCB is completed and before 27971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * restarting the SCRIPTS. 27981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 27991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Another issue is that we need some section of our 28001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * recovery procedures to be somehow uninterruptible but 28011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the SCRIPTS processor does not provides such a 28021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * feature. For this reason, we handle recovery preferently 28031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * from the C code and check against some SCRIPTS critical 28041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sections from the C code. 28051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 28061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Hopefully, the interrupt handling of the driver is now 28071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * able to resist to weird BUS error conditions, but donnot 28081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ask me for any guarantee that it will never fail. :-) 28091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Use at your own decision and risk. 28101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 28111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 281299c9e0a1d6cfe1ba1169a7a81435ee85bc00e4a1Matthew Wilcoxirqreturn_t sym_interrupt(struct Scsi_Host *shost) 28131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 28145111eefa17615bdf17ca00ec2cdca16302c7697eMatthew Wilcox struct sym_data *sym_data = shost_priv(shost); 28155111eefa17615bdf17ca00ec2cdca16302c7697eMatthew Wilcox struct sym_hcb *np = sym_data->ncb; 28165111eefa17615bdf17ca00ec2cdca16302c7697eMatthew Wilcox struct pci_dev *pdev = sym_data->pdev; 28171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char istat, istatc; 28181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char dstat; 28191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_short sist; 28201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 28221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * interrupt on the fly ? 28231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (SCRIPTS may still be running) 28241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 28251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A `dummy read' is needed to ensure that the 28261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * clear of the INTF flag reaches the device 28271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and that posted writes are flushed to memory 28281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * before the scanning of the DONE queue. 28291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Note that SCRIPTS also (dummy) read to memory 28301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * prior to deliver the INTF interrupt condition. 28311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 28321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds istat = INB(np, nc_istat); 28331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (istat & INTF) { 28341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_istat, (istat & SIGP) | INTF | np->istat_sem); 2835cedefa13db502432905c29819c195f46805b13ebTony Battersby istat |= INB(np, nc_istat); /* DUMMY READ */ 28361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (DEBUG_FLAGS & DEBUG_TINY) printf ("F "); 28371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_wakeup_done(np); 28381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 28391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(istat & (SIP|DIP))) 284199c9e0a1d6cfe1ba1169a7a81435ee85bc00e4a1Matthew Wilcox return (istat & INTF) ? IRQ_HANDLED : IRQ_NONE; 28421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 /* We should never get this one */ 28441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (istat & CABRT) 28451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_istat, CABRT); 28461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 28471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 28491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PAR and MA interrupts may occur at the same time, 28501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and we need to know of both in order to handle 28511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this situation properly. We try to unstack SCSI 28521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * interrupts for that reason. BTW, I dislike a LOT 28531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * such a loop inside the interrupt routine. 28541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Even if DMA interrupt stacking is very unlikely to 28551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * happen, we also try unstacking these ones, since 28561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this has no performance impact. 28571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 28581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sist = 0; 28591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dstat = 0; 28601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds istatc = istat; 28611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds do { 28621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (istatc & SIP) 28631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sist |= INW(np, nc_sist); 28641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (istatc & DIP) 28651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dstat |= INB(np, nc_dstat); 28661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds istatc = INB(np, nc_istat); 28671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds istat |= istatc; 2868d68cd75992f95d6977956fb227f02e6d532f3d26Linas Vepstas 2869d68cd75992f95d6977956fb227f02e6d532f3d26Linas Vepstas /* Prevent deadlock waiting on a condition that may 2870d68cd75992f95d6977956fb227f02e6d532f3d26Linas Vepstas * never clear. */ 2871d68cd75992f95d6977956fb227f02e6d532f3d26Linas Vepstas if (unlikely(sist == 0xffff && dstat == 0xff)) { 28725111eefa17615bdf17ca00ec2cdca16302c7697eMatthew Wilcox if (pci_channel_offline(pdev)) 287399c9e0a1d6cfe1ba1169a7a81435ee85bc00e4a1Matthew Wilcox return IRQ_NONE; 2874d68cd75992f95d6977956fb227f02e6d532f3d26Linas Vepstas } 28751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } while (istatc & (SIP|DIP)); 28761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (DEBUG_FLAGS & DEBUG_TINY) 28781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf ("<%d|%x:%x|%x:%x>", 28791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (int)INB(np, nc_scr0), 28801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dstat,sist, 28811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned)INL(np, nc_dsp), 28821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (unsigned)INL(np, nc_dbc)); 28831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 28841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * On paper, a memory read barrier may be needed here to 28851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * prevent out of order LOADs by the CPU from having 28861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * prefetched stale data prior to DMA having occurred. 28871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * And since we are paranoid ... :) 28881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 28891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds MEMORY_READ_BARRIER(); 28901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 28911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 28921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * First, interrupts we want to service cleanly. 28931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 28941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Phase mismatch (MA) is the most frequent interrupt 28951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for chip earlier than the 896 and so we have to service 28961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it as quickly as possible. 28971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A SCSI parity error (PAR) may be combined with a phase 28981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * mismatch condition (MA). 28991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Programmed interrupts (SIR) are used to call the C code 29001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * from SCRIPTS. 29011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The single step interrupt (SSI) is not used in this 29021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * driver. 29031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 29041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(sist & (STO|GEN|HTH|SGE|UDC|SBMC|RST)) && 29051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !(dstat & (MDPE|BF|ABRT|IID))) { 29061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sist & PAR) sym_int_par (np, sist); 29071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (sist & MA) sym_int_ma (np); 29083fb364e089e05c35ead55a08d56d3004193681f6Matthew Wilcox else if (dstat & SIR) sym_int_sir(np); 29091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (dstat & SSI) OUTONB_STD(); 29101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else goto unknown_int; 291199c9e0a1d6cfe1ba1169a7a81435ee85bc00e4a1Matthew Wilcox return IRQ_HANDLED; 29121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 29131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 29151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Now, interrupts that donnot happen in normal 29161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * situations and that we may need to recover from. 29171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 29181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * On SCSI RESET (RST), we reset everything. 29191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * On SCSI BUS MODE CHANGE (SBMC), we complete all 29201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * active CCBs with RESET status, prepare all devices 29211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for negotiating again and restart the SCRIPTS. 29221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * On STO and UDC, we complete the CCB with the corres- 29231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ponding status and restart the SCRIPTS. 29241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 29251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sist & RST) { 29261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf("%s: SCSI BUS reset detected.\n", sym_name(np)); 29275111eefa17615bdf17ca00ec2cdca16302c7697eMatthew Wilcox sym_start_up(shost, 1); 292899c9e0a1d6cfe1ba1169a7a81435ee85bc00e4a1Matthew Wilcox return IRQ_HANDLED; 29291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 29301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_ctest3, np->rv_ctest3 | CLF); /* clear dma fifo */ 29321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_stest3, TE|CSF); /* clear scsi fifo */ 29331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(sist & (GEN|HTH|SGE)) && 29351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds !(dstat & (MDPE|BF|ABRT|IID))) { 29365111eefa17615bdf17ca00ec2cdca16302c7697eMatthew Wilcox if (sist & SBMC) sym_int_sbmc(shost); 29371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (sist & STO) sym_int_sto (np); 29381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (sist & UDC) sym_int_udc (np); 29391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else goto unknown_int; 294099c9e0a1d6cfe1ba1169a7a81435ee85bc00e4a1Matthew Wilcox return IRQ_HANDLED; 29411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 29421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 29441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Now, interrupts we are not able to recover cleanly. 29451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 29461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Log message for hard errors. 29471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Reset everything. 29481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 29491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29505111eefa17615bdf17ca00ec2cdca16302c7697eMatthew Wilcox sym_log_hard_error(shost, sist, dstat); 29511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((sist & (GEN|HTH|SGE)) || 29531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (dstat & (MDPE|BF|ABRT|IID))) { 29541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_start_reset(np); 295599c9e0a1d6cfe1ba1169a7a81435ee85bc00e4a1Matthew Wilcox return IRQ_HANDLED; 29561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 29571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsunknown_int: 29591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 29601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We just miss the cause of the interrupt. :( 29611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Print a message. The timeout will do the real work. 29621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 29631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf( "%s: unknown interrupt(s) ignored, " 29641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "ISTAT=0x%x DSTAT=0x%x SIST=0x%x\n", 29651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_name(np), istat, dstat, sist); 296699c9e0a1d6cfe1ba1169a7a81435ee85bc00e4a1Matthew Wilcox return IRQ_NONE; 29671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 29681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 29701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Dequeue from the START queue all CCBs that match 29711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a given target/lun/task condition (-1 means all), 29721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and move them from the BUSY queue to the COMP queue 297353222b906903fd861dc24ebccfa07ee125941313Matthew Wilcox * with DID_SOFT_ERROR status condition. 29741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This function is used during error handling/recovery. 29751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * It is called with SCRIPTS not running. 29761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 29771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 29781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssym_dequeue_from_squeue(struct sym_hcb *np, int i, int target, int lun, int task) 29791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 29801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int j; 29811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_ccb *cp; 29821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 29841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Make sure the starting index is within range. 29851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 29861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds assert((i >= 0) && (i < 2*MAX_QUEUE)); 29871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 29881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 29891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Walk until end of START queue and dequeue every job 29901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that matches the target/lun/task condition. 29911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 29921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds j = i; 29931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (i != np->squeueput) { 29941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp = sym_ccb_from_dsa(np, scr_to_cpu(np->squeue[i])); 29951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds assert(cp); 29961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef SYM_CONF_IARB_SUPPORT 29971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Forget hints for IARB, they may be no longer relevant */ 29981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->host_flags &= ~HF_HINT_IARB; 29991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 30001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((target == -1 || cp->target == target) && 30011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (lun == -1 || cp->lun == lun) && 30021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (task == -1 || cp->tag == task)) { 300353222b906903fd861dc24ebccfa07ee125941313Matthew Wilcox sym_set_cam_status(cp->cmd, DID_SOFT_ERROR); 30041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_remque(&cp->link_ccbq); 30051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_insque_tail(&cp->link_ccbq, &np->comp_ccbq); 30061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 30071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 30081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i != j) 30091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->squeue[j] = np->squeue[i]; 30101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((j += 2) >= MAX_QUEUE*2) j = 0; 30111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 30121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((i += 2) >= MAX_QUEUE*2) i = 0; 30131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 30141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i != j) /* Copy back the idle task if needed */ 30151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->squeue[j] = np->squeue[i]; 30161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->squeueput = j; /* Update our current start queue pointer */ 30171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return (i - j) / 2; 30191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 30201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 30221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * chip handler for bad SCSI status condition 30231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 30241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * In case of bad SCSI status, we unqueue all the tasks 30251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * currently queued to the controller but not yet started 30261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and then restart the SCRIPTS processor immediately. 30271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 30281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * QUEUE FULL and BUSY conditions are handled the same way. 30291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Basically all the not yet started tasks are requeued in 30301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * device queue and the queue is frozen until a completion. 30311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 30321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For CHECK CONDITION and COMMAND TERMINATED status, we use 30331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the CCB of the failed command to prepare a REQUEST SENSE 30341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SCSI command and queue it to the controller queue. 30351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 30361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SCRATCHA is assumed to have been loaded with STARTPOS 30371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * before the SCRIPTS called the C code. 30381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 30391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sym_sir_bad_scsi_status(struct sym_hcb *np, int num, struct sym_ccb *cp) 30401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 30411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 startp; 30421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char s_status = cp->ssss_status; 30431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char h_flags = cp->host_flags; 30441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int msglen; 30451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 30461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 30481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Compute the index of the next job to start from SCRIPTS. 30491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 30501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = (INL(np, nc_scratcha) - np->squeue_ba) / 4; 30511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 30531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The last CCB queued used for IARB hint may be 30541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * no longer relevant. Forget it. 30551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 30561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef SYM_CONF_IARB_SUPPORT 30571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->last_cp) 30581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->last_cp = 0; 30591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 30601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 30621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Now deal with the SCSI status. 30631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 30641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch(s_status) { 30651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case S_BUSY: 30661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case S_QUEUE_FULL: 30671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sym_verbose >= 2) { 30681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_print_addr(cp->cmd, "%s\n", 30691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds s_status == S_BUSY ? "BUSY" : "QUEUE FULL\n"); 30701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 30711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: /* S_INT, S_INT_COND_MET, S_CONFLICT */ 30721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_complete_error (np, cp); 30731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 30741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case S_TERMINATED: 30751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case S_CHECK_COND: 30761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 30771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we get an SCSI error when requesting sense, give up. 30781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 30791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (h_flags & HF_SENSE) { 30801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_complete_error (np, cp); 30811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 30821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 30831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 30851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Dequeue all queued CCBs for that device not yet started, 30861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and restart the SCRIPTS processor immediately. 30871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 30881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_dequeue_from_squeue(np, i, cp->target, cp->lun, -1); 30891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL_DSP(np, SCRIPTA_BA(np, start)); 30901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 30921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Save some info of the actual IO. 30931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Compute the data residual. 30941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 30951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->sv_scsi_status = cp->ssss_status; 30961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->sv_xerr_status = cp->xerr_status; 30971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->sv_resid = sym_compute_residual(np, cp); 30981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 31001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Prepare all needed data structures for 31011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * requesting sense data. 31021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 31031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->scsi_smsg2[0] = IDENTIFY(0, cp->lun); 31051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msglen = 1; 31061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 31081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we are currently using anything different from 31091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * async. 8 bit data transfers with that target, 31101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * start a negotiation, since the device may want 31111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to report us a UNIT ATTENTION condition due to 31121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a cause we currently ignore, and we donnot want 31131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to be stuck with WIDE and/or SYNC data transfer. 31141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 31151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cp->nego_status is filled by sym_prepare_nego(). 31161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 31171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->nego_status = 0; 31181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msglen += sym_prepare_nego(np, cp, &cp->scsi_smsg2[msglen]); 31191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 31201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Message table indirect structure. 31211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 312253222b906903fd861dc24ebccfa07ee125941313Matthew Wilcox cp->phys.smsg.addr = CCB_BA(cp, scsi_smsg2); 31231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->phys.smsg.size = cpu_to_scr(msglen); 31241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 31261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sense command 31271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 312853222b906903fd861dc24ebccfa07ee125941313Matthew Wilcox cp->phys.cmd.addr = CCB_BA(cp, sensecmd); 31291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->phys.cmd.size = cpu_to_scr(6); 31301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 31321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * patch requested size into sense command 31331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 31341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->sensecmd[0] = REQUEST_SENSE; 31351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->sensecmd[1] = 0; 31361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp->cmd->device->scsi_level <= SCSI_2 && cp->lun <= 7) 31371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->sensecmd[1] = cp->lun << 5; 31381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->sensecmd[4] = SYM_SNS_BBUF_LEN; 31391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->data_len = SYM_SNS_BBUF_LEN; 31401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 31421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sense data 31431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 31441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memset(cp->sns_bbuf, 0, SYM_SNS_BBUF_LEN); 314553222b906903fd861dc24ebccfa07ee125941313Matthew Wilcox cp->phys.sense.addr = CCB_BA(cp, sns_bbuf); 31461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->phys.sense.size = cpu_to_scr(SYM_SNS_BBUF_LEN); 31471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 31491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * requeue the command. 31501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 31511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds startp = SCRIPTB_BA(np, sdata_in); 31521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->phys.head.savep = cpu_to_scr(startp); 31541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->phys.head.lastp = cpu_to_scr(startp); 31551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->startp = cpu_to_scr(startp); 31561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->goalp = cpu_to_scr(startp + 16); 31571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->host_xflags = 0; 31591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->host_status = cp->nego_status ? HS_NEGOTIATE : HS_BUSY; 31601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->ssss_status = S_ILLEGAL; 31611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->host_flags = (HF_SENSE|HF_DATA_IN); 31621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->xerr_status = 0; 31631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->extra_bytes = 0; 31641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->phys.head.go.start = cpu_to_scr(SCRIPTA_BA(np, select)); 31661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 31681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Requeue the command. 31691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 31701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_put_start_queue(np, cp); 31711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 31731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Give back to upper layer everything we have dequeued. 31741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 31751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_flush_comp_queue(np, 0); 31761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 31771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 31781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 31791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 31811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * After a device has accepted some management message 31821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * as BUS DEVICE RESET, ABORT TASK, etc ..., or when 31831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a device signals a UNIT ATTENTION condition, some 31841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * tasks are thrown away by the device. We are required 31851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to reflect that on our tasks list since the device 31861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * will never complete these tasks. 31871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 31881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This function move from the BUSY queue to the COMP 31891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * queue all disconnected CCBs for a given target that 31901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * match the following criteria: 31911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - lun=-1 means any logical UNIT otherwise a given one. 31921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - task=-1 means any task, otherwise a given one. 31931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 31941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint sym_clear_tasks(struct sym_hcb *np, int cam_status, int target, int lun, int task) 31951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 31961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SYM_QUEHEAD qtmp, *qp; 31971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i = 0; 31981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_ccb *cp; 31991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 32011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Move the entire BUSY queue to our temporary queue. 32021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 32031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_que_init(&qtmp); 32041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_que_splice(&np->busy_ccbq, &qtmp); 32051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_que_init(&np->busy_ccbq); 32061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 32081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Put all CCBs that matches our criteria into 32091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the COMP queue and put back other ones into 32101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the BUSY queue. 32111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3212172c122df5186e7cbd413d61757ff90267331002Harvey Harrison while ((qp = sym_remque_head(&qtmp)) != NULL) { 32131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scsi_cmnd *cmd; 32141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); 32151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd = cp->cmd; 32161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp->host_status != HS_DISCONNECT || 32171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->target != target || 32181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (lun != -1 && cp->lun != lun) || 32191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (task != -1 && 32201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (cp->tag != NO_TAG && cp->scsi_smsg[2] != task))) { 32211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_insque_tail(&cp->link_ccbq, &np->busy_ccbq); 32221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 32231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 32241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_insque_tail(&cp->link_ccbq, &np->comp_ccbq); 32251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Preserve the software timeout condition */ 322753222b906903fd861dc24ebccfa07ee125941313Matthew Wilcox if (sym_get_cam_status(cmd) != DID_TIME_OUT) 32281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_set_cam_status(cmd, cam_status); 32291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ++i; 32301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 32311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsprintf("XXXX TASK @%p CLEARED\n", cp); 32321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 32331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 32341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return i; 32351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 32361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 32381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * chip handler for TASKS recovery 32391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 32401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We cannot safely abort a command, while the SCRIPTS 32411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * processor is running, since we just would be in race 32421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * with it. 32431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 32441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * As long as we have tasks to abort, we keep the SEM 32451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bit set in the ISTAT. When this bit is set, the 32461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SCRIPTS processor interrupts (SIR_SCRIPT_STOPPED) 32471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * each time it enters the scheduler. 32481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 32491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we have to reset a target, clear tasks of a unit, 32501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * or to perform the abort of a disconnected job, we 32511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * restart the SCRIPTS for selecting the target. Once 32521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * selected, the SCRIPTS interrupts (SIR_TARGET_SELECTED). 32531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If it loses arbitration, the SCRIPTS will interrupt again 32541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the next time it will enter its scheduler, and so on ... 32551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 32561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * On SIR_TARGET_SELECTED, we scan for the more 32571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * appropriate thing to do: 32581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 32591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - If nothing, we just sent a M_ABORT message to the 32601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * target to get rid of the useless SCSI bus ownership. 32611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * According to the specs, no tasks shall be affected. 32621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - If the target is to be reset, we send it a M_RESET 32631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * message. 32641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - If a logical UNIT is to be cleared , we send the 32651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * IDENTIFY(lun) + M_ABORT. 32661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - If an untagged task is to be aborted, we send the 32671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * IDENTIFY(lun) + M_ABORT. 32681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - If a tagged task is to be aborted, we send the 32691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * IDENTIFY(lun) + task attributes + M_ABORT_TAG. 32701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 32711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Once our 'kiss of death' :) message has been accepted 32721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * by the target, the SCRIPTS interrupts again 32731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (SIR_ABORT_SENT). On this interrupt, we complete 32741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * all the CCBs that should have been aborted by the 32751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * target according to our message. 32761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 32771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sym_sir_task_recovery(struct sym_hcb *np, int num) 32781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 32791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SYM_QUEHEAD *qp; 32801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_ccb *cp; 32811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_tcb *tp = NULL; /* gcc isn't quite smart enough yet */ 32821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scsi_target *starget; 32831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int target=-1, lun=-1, task; 32841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, k; 32851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 32861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch(num) { 32871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 32881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The SCRIPTS processor stopped before starting 32891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the next command in order to allow us to perform 32901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * some task recovery. 32911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 32921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIR_SCRIPT_STOPPED: 32931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 32941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Do we have any target to reset or unit to clear ? 32951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 32961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0 ; i < SYM_CONF_MAX_TARGET ; i++) { 32971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp = &np->target[i]; 32981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tp->to_reset || 32991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (tp->lun0p && tp->lun0p->to_clear)) { 33001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds target = i; 33011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 33021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 33031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!tp->lunmp) 33041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 33051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (k = 1 ; k < SYM_CONF_MAX_LUN ; k++) { 33061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tp->lunmp[k] && tp->lunmp[k]->to_clear) { 33071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds target = i; 33081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 33091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 33101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 33111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (target != -1) 33121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 33131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 33141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 33161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If not, walk the busy queue for any 33171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * disconnected CCB to be aborted. 33181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 33191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (target == -1) { 33201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) { 33211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp = sym_que_entry(qp,struct sym_ccb,link_ccbq); 33221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp->host_status != HS_DISCONNECT) 33231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 33241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp->to_abort) { 33251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds target = cp->target; 33261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 33271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 33281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 33291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 33301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 33321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If some target is to be selected, 33331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * prepare and start the selection. 33341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 33351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (target != -1) { 33361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp = &np->target[target]; 33371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->abrt_sel.sel_id = target; 33381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->abrt_sel.sel_scntl3 = tp->head.wval; 33391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->abrt_sel.sel_sxfer = tp->head.sval; 33401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL(np, nc_dsa, np->hcb_ba); 33411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL_DSP(np, SCRIPTB_BA(np, sel_for_abort)); 33421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 33431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 33441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 33461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Now look for a CCB to abort that haven't started yet. 33471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Btw, the SCRIPTS processor is still stopped, so 33481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we are not in race. 33491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 33501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = 0; 33511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp = NULL; 33521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) { 33531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); 33541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp->host_status != HS_BUSY && 33551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->host_status != HS_NEGOTIATE) 33561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 33571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!cp->to_abort) 33581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 33591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef SYM_CONF_IARB_SUPPORT 33601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 33611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we are using IMMEDIATE ARBITRATION, we donnot 33621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * want to cancel the last queued CCB, since the 33631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SCRIPTS may have anticipated the selection. 33641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 33651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp == np->last_cp) { 33661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->to_abort = 0; 33671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 33681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 33691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 33701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = 1; /* Means we have found some */ 33711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 33721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 33731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!i) { 33741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 33751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We are done, so we donnot need 33761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to synchronize with the SCRIPTS anylonger. 33771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Remove the SEM flag from the ISTAT. 33781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 33791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->istat_sem = 0; 33801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_istat, SIGP); 33811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 33821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 33831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 33841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Compute index of next position in the start 33851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * queue the SCRIPTS intends to start and dequeue 33861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * all CCBs for that device that haven't been started. 33871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 33881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = (INL(np, nc_scratcha) - np->squeue_ba) / 4; 33891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = sym_dequeue_from_squeue(np, i, cp->target, cp->lun, -1); 33901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 33911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 33921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Make sure at least our IO to abort has been dequeued. 33931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 33941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef SYM_OPT_HANDLE_DEVICE_QUEUEING 339553222b906903fd861dc24ebccfa07ee125941313Matthew Wilcox assert(i && sym_get_cam_status(cp->cmd) == DID_SOFT_ERROR); 33961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 33971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_remque(&cp->link_ccbq); 33981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_insque_tail(&cp->link_ccbq, &np->comp_ccbq); 33991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 34001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 34011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Keep track in cam status of the reason of the abort. 34021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 34031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp->to_abort == 2) 340453222b906903fd861dc24ebccfa07ee125941313Matthew Wilcox sym_set_cam_status(cp->cmd, DID_TIME_OUT); 34051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 340653222b906903fd861dc24ebccfa07ee125941313Matthew Wilcox sym_set_cam_status(cp->cmd, DID_ABORT); 34071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 34091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Complete with error everything that we have dequeued. 34101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 34111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_flush_comp_queue(np, 0); 34121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 34131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 34141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The SCRIPTS processor has selected a target 34151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we may have some manual recovery to perform for. 34161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 34171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIR_TARGET_SELECTED: 34181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds target = INB(np, nc_sdid) & 0xf; 34191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp = &np->target[target]; 34201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->abrt_tbl.addr = cpu_to_scr(vtobus(np->abrt_msg)); 34221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 34241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the target is to be reset, prepare a 34251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * M_RESET message and clear the to_reset flag 34261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * since we donnot expect this operation to fail. 34271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 34281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tp->to_reset) { 34291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->abrt_msg[0] = M_RESET; 34301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->abrt_tbl.size = 1; 34311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->to_reset = 0; 34321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 34331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 34341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 34361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Otherwise, look for some logical unit to be cleared. 34371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 34381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tp->lun0p && tp->lun0p->to_clear) 34391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lun = 0; 34401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (tp->lunmp) { 34411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (k = 1 ; k < SYM_CONF_MAX_LUN ; k++) { 34421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tp->lunmp[k] && tp->lunmp[k]->to_clear) { 34431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lun = k; 34441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 34451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 34461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 34471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 34481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 34501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If a logical unit is to be cleared, prepare 34511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * an IDENTIFY(lun) + ABORT MESSAGE. 34521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 34531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lun != -1) { 34541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_lcb *lp = sym_lp(tp, lun); 34551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->to_clear = 0; /* We don't expect to fail here */ 34561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->abrt_msg[0] = IDENTIFY(0, lun); 34571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->abrt_msg[1] = M_ABORT; 34581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->abrt_tbl.size = 2; 34591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 34601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 34611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 34631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Otherwise, look for some disconnected job to 34641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * abort for this target. 34651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 34661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = 0; 34671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp = NULL; 34681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) { 34691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); 34701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp->host_status != HS_DISCONNECT) 34711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 34721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp->target != target) 34731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 34741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!cp->to_abort) 34751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds continue; 34761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = 1; /* Means we have some */ 34771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 34781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 34791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 34811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we have none, probably since the device has 34821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * completed the command before we won abitration, 34831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * send a M_ABORT message without IDENTIFY. 34841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * According to the specs, the device must just 34851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * disconnect the BUS and not abort any task. 34861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 34871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!i) { 34881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->abrt_msg[0] = M_ABORT; 34891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->abrt_tbl.size = 1; 34901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 34911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 34921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 34941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We have some task to abort. 34951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set the IDENTIFY(lun) 34961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 34971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->abrt_msg[0] = IDENTIFY(0, cp->lun); 34981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 34991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 35001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we want to abort an untagged command, we 35011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * will send a IDENTIFY + M_ABORT. 35021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Otherwise (tagged command), we will send 35031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a IDENTITFY + task attributes + ABORT TAG. 35041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 35051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp->tag == NO_TAG) { 35061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->abrt_msg[1] = M_ABORT; 35071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->abrt_tbl.size = 2; 35081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 35091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->abrt_msg[1] = cp->scsi_smsg[1]; 35101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->abrt_msg[2] = cp->scsi_smsg[2]; 35111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->abrt_msg[3] = M_ABORT_TAG; 35121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->abrt_tbl.size = 4; 35131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 35141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 35151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Keep track of software timeout condition, since the 35161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * peripheral driver may not count retries on abort 35171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * conditions not due to timeout. 35181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 35191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp->to_abort == 2) 352053222b906903fd861dc24ebccfa07ee125941313Matthew Wilcox sym_set_cam_status(cp->cmd, DID_TIME_OUT); 35211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->to_abort = 0; /* We donnot expect to fail here */ 35221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 35231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 35251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The target has accepted our message and switched 35261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to BUS FREE phase as we expected. 35271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 35281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIR_ABORT_SENT: 35291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds target = INB(np, nc_sdid) & 0xf; 35301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp = &np->target[target]; 353153222b906903fd861dc24ebccfa07ee125941313Matthew Wilcox starget = tp->starget; 35321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 35341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ** If we didn't abort anything, leave here. 35351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 35361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->abrt_msg[0] == M_ABORT) 35371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 35381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 35401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we sent a M_RESET, then a hardware reset has 35411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * been performed by the target. 35421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - Reset everything to async 8 bit 35431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - Tell ourself to negotiate next time :-) 35441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - Prepare to clear all disconnected CCBs for 35451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this target from our task list (lun=task=-1) 35461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 35471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lun = -1; 35481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds task = -1; 35491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->abrt_msg[0] == M_RESET) { 35501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->head.sval = 0; 35511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->head.wval = np->rv_scntl3; 35521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->head.uval = 0; 35531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spi_period(starget) = 0; 35541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spi_offset(starget) = 0; 35551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spi_width(starget) = 0; 35561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spi_iu(starget) = 0; 35571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spi_dt(starget) = 0; 35581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds spi_qas(starget) = 0; 35591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->tgoal.check_nego = 1; 356049799fee82b4f78c45b1926be24e45b5cf667083Aaro Koskinen tp->tgoal.renego = 0; 35611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 35621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 35641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Otherwise, check for the LUN and TASK(s) 35651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * concerned by the cancelation. 35661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If it is not ABORT_TAG then it is CLEAR_QUEUE 35671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * or an ABORT message :-) 35681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 35691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 35701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lun = np->abrt_msg[0] & 0x3f; 35711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->abrt_msg[1] == M_ABORT_TAG) 35721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds task = np->abrt_msg[2]; 35731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 35741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 35761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Complete all the CCBs the device should have 35771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * aborted due to our 'kiss of death' message. 35781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 35791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = (INL(np, nc_scratcha) - np->squeue_ba) / 4; 35801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_dequeue_from_squeue(np, i, target, lun, -1); 358153222b906903fd861dc24ebccfa07ee125941313Matthew Wilcox sym_clear_tasks(np, DID_ABORT, target, lun, task); 35821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_flush_comp_queue(np, 0); 35831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 35851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we sent a BDR, make upper layer aware of that. 35861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 35871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->abrt_msg[0] == M_RESET) 3588aac6a5a34050a97016290f341e8de0a09f3a8f8cMatthew Wilcox starget_printk(KERN_NOTICE, starget, 3589aac6a5a34050a97016290f341e8de0a09f3a8f8cMatthew Wilcox "has been reset\n"); 35901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 35911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 35921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 35941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Print to the log the message we intend to send. 35951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 35961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (num == SIR_TARGET_SELECTED) { 359753222b906903fd861dc24ebccfa07ee125941313Matthew Wilcox dev_info(&tp->starget->dev, "control msgout:"); 35981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_printl_hex(np->abrt_msg, np->abrt_tbl.size); 35991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->abrt_tbl.size = cpu_to_scr(np->abrt_tbl.size); 36001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 36011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 36031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Let the SCRIPTS processor continue. 36041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 36051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTONB_STD(); 36061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 36071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 36091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Gerard's alchemy:) that deals with with the data 36101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pointer for both MDP and the residual calculation. 36111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 36121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * I didn't want to bloat the code by more than 200 36131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * lines for the handling of both MDP and the residual. 36141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This has been achieved by using a data pointer 36151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * representation consisting in an index in the data 36161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * array (dp_sg) and a negative offset (dp_ofs) that 36171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * have the following meaning: 36181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 36191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - dp_sg = SYM_CONF_MAX_SG 36201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we are at the end of the data script. 36211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - dp_sg < SYM_CONF_MAX_SG 36221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dp_sg points to the next entry of the scatter array 36231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we want to transfer. 36241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - dp_ofs < 0 36251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dp_ofs represents the residual of bytes of the 36261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * previous entry scatter entry we will send first. 36271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * - dp_ofs = 0 36281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * no residual to send first. 36291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 36301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The function sym_evaluate_dp() accepts an arbitray 36311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * offset (basically from the MDP message) and returns 36321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the corresponding values of dp_sg and dp_ofs. 36331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 36341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int sym_evaluate_dp(struct sym_hcb *np, struct sym_ccb *cp, u32 scr, int *ofs) 36361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 36371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 dp_scr; 36381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int dp_ofs, dp_sg, dp_sgmin; 36391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int tmp; 36401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_pmc *pm; 36411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 36431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Compute the resulted data pointer in term of a script 36441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * address within some DATA script and a signed byte offset. 36451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 36461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dp_scr = scr; 36471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dp_ofs = *ofs; 36481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dp_scr == SCRIPTA_BA(np, pm0_data)) 36491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pm = &cp->phys.pm0; 36501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (dp_scr == SCRIPTA_BA(np, pm1_data)) 36511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pm = &cp->phys.pm1; 36521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 36531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pm = NULL; 36541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (pm) { 36561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dp_scr = scr_to_cpu(pm->ret); 3657e2230eac17486e2ee07091d54d898eb40bcd0fddMatthew Wilcox dp_ofs -= scr_to_cpu(pm->sg.size) & 0x00ffffff; 36581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 36591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 36611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we are auto-sensing, then we are done. 36621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 36631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp->host_flags & HF_SENSE) { 36641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *ofs = dp_ofs; 36651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 36661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 36671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 36691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Deduce the index of the sg entry. 36701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Keep track of the index of the first valid entry. 36711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If result is dp_sg = SYM_CONF_MAX_SG, then we are at the 36721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * end of the data. 36731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 367444f30b0f59d628eb6f57cfa9d8ab06da670e5306Matthew Wilcox tmp = scr_to_cpu(cp->goalp); 36751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dp_sg = SYM_CONF_MAX_SG; 36761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dp_scr != tmp) 36771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dp_sg -= (tmp - 8 - (int)dp_scr) / (2*4); 36781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dp_sgmin = SYM_CONF_MAX_SG - cp->segments; 36791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 36811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Move to the sg entry the data pointer belongs to. 36821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 36831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we are inside the data area, we expect result to be: 36841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 36851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Either, 36861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dp_ofs = 0 and dp_sg is the index of the sg entry 36871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the data pointer belongs to (or the end of the data) 36881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Or, 36891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * dp_ofs < 0 and dp_sg is the index of the sg entry 36901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the data pointer belongs to + 1. 36911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 36921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dp_ofs < 0) { 36931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int n; 36941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (dp_sg > dp_sgmin) { 36951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds --dp_sg; 36961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = scr_to_cpu(cp->phys.data[dp_sg].size); 36971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds n = dp_ofs + (tmp & 0xffffff); 36981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (n > 0) { 36991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ++dp_sg; 37001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 37011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 37021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dp_ofs = n; 37031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 37041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 37051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (dp_ofs > 0) { 37061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (dp_sg < SYM_CONF_MAX_SG) { 37071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = scr_to_cpu(cp->phys.data[dp_sg].size); 37081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dp_ofs -= (tmp & 0xffffff); 37091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ++dp_sg; 37101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dp_ofs <= 0) 37111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 37121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 37131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 37141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 37161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Make sure the data pointer is inside the data area. 37171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If not, return some error. 37181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 37191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dp_sg < dp_sgmin || (dp_sg == dp_sgmin && dp_ofs < 0)) 37201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_err; 37211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else if (dp_sg > SYM_CONF_MAX_SG || 37221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (dp_sg == SYM_CONF_MAX_SG && dp_ofs > 0)) 37231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_err; 37241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 37261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Save the extreme pointer if needed. 37271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 37281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dp_sg > cp->ext_sg || 37291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (dp_sg == cp->ext_sg && dp_ofs > cp->ext_ofs)) { 37301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->ext_sg = dp_sg; 37311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->ext_ofs = dp_ofs; 37321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 37331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 37351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Return data. 37361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 37371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *ofs = dp_ofs; 37381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return dp_sg; 37391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_err: 37411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 37421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 37431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 37451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * chip handler for MODIFY DATA POINTER MESSAGE 37461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 37471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We also call this function on IGNORE WIDE RESIDUE 37481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * messages that do not match a SWIDE full condition. 37491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Btw, we assume in that situation that such a message 37501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * is equivalent to a MODIFY DATA POINTER (offset=-1). 37511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 37521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sym_modify_dp(struct sym_hcb *np, struct sym_tcb *tp, struct sym_ccb *cp, int ofs) 37541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 37551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int dp_ofs = ofs; 37561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 dp_scr = sym_get_script_dp (np, cp); 37571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 dp_ret; 37581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 tmp; 37591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char hflags; 37601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int dp_sg; 37611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_pmc *pm; 37621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 37641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Not supported for auto-sense. 37651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 37661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp->host_flags & HF_SENSE) 37671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_reject; 37681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 37701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Apply our alchemy:) (see comments in sym_evaluate_dp()), 37711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to the resulted data pointer. 37721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 37731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dp_sg = sym_evaluate_dp(np, cp, dp_scr, &dp_ofs); 37741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dp_sg < 0) 37751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_reject; 37761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 37781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * And our alchemy:) allows to easily calculate the data 37791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * script address we want to return for the next data phase. 37801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 378144f30b0f59d628eb6f57cfa9d8ab06da670e5306Matthew Wilcox dp_ret = cpu_to_scr(cp->goalp); 37821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dp_ret = dp_ret - 8 - (SYM_CONF_MAX_SG - dp_sg) * (2*4); 37831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 37851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If offset / scatter entry is zero we donnot need 37861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a context for the new current data pointer. 37871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 37881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (dp_ofs == 0) { 37891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dp_scr = dp_ret; 37901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_ok; 37911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 37921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 37941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get a context for the new current data pointer. 37951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 37961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hflags = INB(np, HF_PRT); 37971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (hflags & HF_DP_SAVED) 37991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hflags ^= HF_ACT_PM; 38001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!(hflags & HF_ACT_PM)) { 38021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pm = &cp->phys.pm0; 38031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dp_scr = SCRIPTA_BA(np, pm0_data); 38041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 38051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 38061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pm = &cp->phys.pm1; 38071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dp_scr = SCRIPTA_BA(np, pm1_data); 38081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 38091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hflags &= ~(HF_DP_SAVED); 38111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, HF_PRT, hflags); 38131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 38151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set up the new current data pointer. 38161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ofs < 0 there, and for the next data phase, we 38171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * want to transfer part of the data of the sg entry 38181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * corresponding to index dp_sg-1 prior to returning 38191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to the main data script. 38201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 38211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pm->ret = cpu_to_scr(dp_ret); 38221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = scr_to_cpu(cp->phys.data[dp_sg-1].addr); 38231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp += scr_to_cpu(cp->phys.data[dp_sg-1].size) + dp_ofs; 38241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pm->sg.addr = cpu_to_scr(tmp); 38251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds pm->sg.size = cpu_to_scr(-dp_ofs); 38261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_ok: 38281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_set_script_dp (np, cp, dp_scr); 38291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL_DSP(np, SCRIPTA_BA(np, clrack)); 38301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 38311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_reject: 38331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL_DSP(np, SCRIPTB_BA(np, msg_bad)); 38341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 38351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 38381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * chip calculation of the data residual. 38391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 38401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * As I used to say, the requirement of data residual 38411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * in SCSI is broken, useless and cannot be achieved 38421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * without huge complexity. 38431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * But most OSes and even the official CAM require it. 38441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * When stupidity happens to be so widely spread inside 38451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a community, it gets hard to convince. 38461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 38471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Anyway, I don't care, since I am not going to use 38481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * any software that considers this data residual as 38491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a relevant information. :) 38501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 38511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint sym_compute_residual(struct sym_hcb *np, struct sym_ccb *cp) 38531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 38541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int dp_sg, dp_sgmin, resid = 0; 38551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int dp_ofs = 0; 38561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 38581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Check for some data lost or just thrown away. 38591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We are not required to be quite accurate in this 38601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * situation. Btw, if we are odd for output and the 38611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * device claims some more data, it may well happen 38621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * than our residual be zero. :-) 38631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 38641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp->xerr_status & (XE_EXTRA_DATA|XE_SODL_UNRUN|XE_SWIDE_OVRUN)) { 38651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp->xerr_status & XE_EXTRA_DATA) 38661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds resid -= cp->extra_bytes; 38671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp->xerr_status & XE_SODL_UNRUN) 38681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ++resid; 38691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp->xerr_status & XE_SWIDE_OVRUN) 38701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds --resid; 38711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 38721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 38741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If all data has been transferred, 38751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * there is no residual. 38761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 387744f30b0f59d628eb6f57cfa9d8ab06da670e5306Matthew Wilcox if (cp->phys.head.lastp == cp->goalp) 38781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return resid; 38791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 38811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If no data transfer occurs, or if the data 38821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pointer is weird, return full residual. 38831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 38841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp->startp == cp->phys.head.lastp || 38851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_evaluate_dp(np, cp, scr_to_cpu(cp->phys.head.lastp), 38861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds &dp_ofs) < 0) { 38873dfcb701e1ff7aa21d6623e46b6ec3f7d0d306e1Tony Battersby return cp->data_len - cp->odd_byte_adjustment; 38881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 38891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 38911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we were auto-sensing, then we are done. 38921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 38931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp->host_flags & HF_SENSE) { 38941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -dp_ofs; 38951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 38961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 38971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 38981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We are now full comfortable in the computation 38991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of the data residual (2's complement). 39001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 39011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dp_sgmin = SYM_CONF_MAX_SG - cp->segments; 39021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds resid = -cp->ext_ofs; 39031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (dp_sg = cp->ext_sg; dp_sg < SYM_CONF_MAX_SG; ++dp_sg) { 39041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int tmp = scr_to_cpu(cp->phys.data[dp_sg].size); 39051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds resid += (tmp & 0xffffff); 39061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 39071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 390853222b906903fd861dc24ebccfa07ee125941313Matthew Wilcox resid -= cp->odd_byte_adjustment; 390953222b906903fd861dc24ebccfa07ee125941313Matthew Wilcox 39101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 39111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Hopefully, the result is not too wrong. 39121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 39131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return resid; 39141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 39151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 39171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Negotiation for WIDE and SYNCHRONOUS DATA TRANSFER. 39181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 39191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * When we try to negotiate, we append the negotiation message 39201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to the identify and (maybe) simple tag message. 39211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The host status field is set to HS_NEGOTIATE to mark this 39221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * situation. 39231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 39241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the target doesn't answer this message immediately 39251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (as required by the standard), the SIR_NEGO_FAILED interrupt 39261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * will be raised eventually. 39271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The handler removes the HS_NEGOTIATE status, and sets the 39281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * negotiated value to the default (async / nowide). 39291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 39301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we receive a matching answer immediately, we check it 39311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for validity, and set the values. 39321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 39331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we receive a Reject message immediately, we assume the 39341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * negotiation has failed, and fall back to standard values. 39351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 39361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we receive a negotiation message while not in HS_NEGOTIATE 39371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * state, it's a target initiated negotiation. We prepare a 39381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (hopefully) valid answer, set our parameters, and send back 39391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this answer to the target. 39401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 39411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If the target doesn't fetch the answer (no message out phase), 39421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we assume the negotiation has failed, and fall back to default 39431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * settings (SIR_NEGO_PROTO interrupt). 39441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 39451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * When we set the values, we adjust them in all ccbs belonging 39461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to this target, in the controller's register, and in the "phys" 39471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * field of the controller's struct sym_hcb. 39481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 39491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 39511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * chip handler for SYNCHRONOUS DATA TRANSFER REQUEST (SDTR) message. 39521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 39531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 39541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssym_sync_nego_check(struct sym_hcb *np, int req, struct sym_ccb *cp) 39551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 39561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int target = cp->target; 39571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char chg, ofs, per, fak, div; 39581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (DEBUG_FLAGS & DEBUG_NEGO) { 39601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_print_nego_msg(np, target, "sync msgin", np->msgin); 39611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 39621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 39641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get requested values. 39651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 39661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds chg = 0; 39671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds per = np->msgin[3]; 39681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ofs = np->msgin[4]; 39691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 39711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Check values against our limits. 39721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 39731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ofs) { 39741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ofs > np->maxoffs) 39751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {chg = 1; ofs = np->maxoffs;} 39761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 39771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ofs) { 39791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (per < np->minsync) 39801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds {chg = 1; per = np->minsync;} 39811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 39821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 39841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get new chip synchronous parameters value. 39851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 39861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds div = fak = 0; 39871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ofs && sym_getsync(np, 0, per, &div, &fak) < 0) 39881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto reject_it; 39891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (DEBUG_FLAGS & DEBUG_NEGO) { 39911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_print_addr(cp->cmd, 39921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "sdtr: ofs=%d per=%d div=%d fak=%d chg=%d.\n", 39931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ofs, per, div, fak, chg); 39941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 39951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 39971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If it was an answer we want to change, 39981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * then it isn't acceptable. Reject it. 39991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 40001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!req && chg) 40011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto reject_it; 40021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 40041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Apply new values. 40051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 40061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_setsync (np, target, ofs, per, div, fak); 40071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 40091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * It was an answer. We are done. 40101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 40111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!req) 40121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 40131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 40151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * It was a request. Prepare an answer message. 40161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 40176ea3c0b2dac0d6a857d6bc010e544f4c901fff78Matthew Wilcox spi_populate_sync_msg(np->msgout, per, ofs); 40181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (DEBUG_FLAGS & DEBUG_NEGO) { 40201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_print_nego_msg(np, target, "sync msgout", np->msgout); 40211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 40221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->msgin [0] = M_NOOP; 40241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 40261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreject_it: 40281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_setsync (np, target, 0, 0, 0, 0); 40291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 40301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 40311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sym_sync_nego(struct sym_hcb *np, struct sym_tcb *tp, struct sym_ccb *cp) 40331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 40341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int req = 1; 40351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result; 40361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 40381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Request or answer ? 40391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 40401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (INB(np, HS_PRT) == HS_NEGOTIATE) { 40411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, HS_PRT, HS_BUSY); 40421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp->nego_status && cp->nego_status != NS_SYNC) 40431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto reject_it; 40441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req = 0; 40451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 40461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 40481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Check and apply new values. 40491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 40501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = sym_sync_nego_check(np, req, cp); 40511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) /* Not acceptable, reject it */ 40521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto reject_it; 40531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req) { /* Was a request, send response. */ 40541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->nego_status = NS_SYNC; 40551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL_DSP(np, SCRIPTB_BA(np, sdtr_resp)); 40561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 40571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else /* Was a response, we are done. */ 40581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL_DSP(np, SCRIPTA_BA(np, clrack)); 40591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 40601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreject_it: 40621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL_DSP(np, SCRIPTB_BA(np, msg_bad)); 40631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 40641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 40661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * chip handler for PARALLEL PROTOCOL REQUEST (PPR) message. 40671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 40681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 40691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssym_ppr_nego_check(struct sym_hcb *np, int req, int target) 40701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 40711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_tcb *tp = &np->target[target]; 40721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char fak, div; 40731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int dt, chg = 0; 40741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char per = np->msgin[3]; 40761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char ofs = np->msgin[5]; 40771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char wide = np->msgin[6]; 40781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char opts = np->msgin[7] & PPR_OPT_MASK; 40791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (DEBUG_FLAGS & DEBUG_NEGO) { 40811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_print_nego_msg(np, target, "ppr msgin", np->msgin); 40821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 40831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 40851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Check values against our limits. 40861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 40871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (wide > np->maxwide) { 40881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds chg = 1; 40891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wide = np->maxwide; 40901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 40911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!wide || !(np->features & FE_U3EN)) 40921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds opts = 0; 40931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (opts != (np->msgin[7] & PPR_OPT_MASK)) 40951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds chg = 1; 40961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dt = opts & PPR_OPT_DT; 40981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ofs) { 41001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char maxoffs = dt ? np->maxoffs_dt : np->maxoffs; 41011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ofs > maxoffs) { 41021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds chg = 1; 41031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ofs = maxoffs; 41041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 41051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 41061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ofs) { 41081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char minsync = dt ? np->minsync_dt : np->minsync; 41091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (per < minsync) { 41101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds chg = 1; 41111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds per = minsync; 41121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 41131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 41141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 41161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get new chip synchronous parameters value. 41171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 41181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds div = fak = 0; 41191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ofs && sym_getsync(np, dt, per, &div, &fak) < 0) 41201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto reject_it; 41211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 41231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If it was an answer we want to change, 41241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * then it isn't acceptable. Reject it. 41251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 41261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!req && chg) 41271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto reject_it; 41281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 41301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Apply new values. 41311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 41321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_setpprot(np, target, opts, ofs, per, wide, div, fak); 41331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 41351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * It was an answer. We are done. 41361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 41371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!req) 41381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 41391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 41411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * It was a request. Prepare an answer message. 41421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 41436ea3c0b2dac0d6a857d6bc010e544f4c901fff78Matthew Wilcox spi_populate_ppr_msg(np->msgout, per, ofs, wide, opts); 41441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (DEBUG_FLAGS & DEBUG_NEGO) { 41461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_print_nego_msg(np, target, "ppr msgout", np->msgout); 41471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 41481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->msgin [0] = M_NOOP; 41501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 41521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreject_it: 41541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_setpprot (np, target, 0, 0, 0, 0, 0, 0); 41551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 41561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If it is a device response that should result in 41571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ST, we may want to try a legacy negotiation later. 41581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 41591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!req && !opts) { 41601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->tgoal.period = per; 41611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->tgoal.offset = ofs; 41621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->tgoal.width = wide; 41631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->tgoal.iu = tp->tgoal.dt = tp->tgoal.qas = 0; 41641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->tgoal.check_nego = 1; 41651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 41661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 41671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 41681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sym_ppr_nego(struct sym_hcb *np, struct sym_tcb *tp, struct sym_ccb *cp) 41701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 41711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int req = 1; 41721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result; 41731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 41751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Request or answer ? 41761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 41771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (INB(np, HS_PRT) == HS_NEGOTIATE) { 41781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, HS_PRT, HS_BUSY); 41791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp->nego_status && cp->nego_status != NS_PPR) 41801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto reject_it; 41811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req = 0; 41821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 41831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 41851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Check and apply new values. 41861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 41871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = sym_ppr_nego_check(np, req, cp->target); 41881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) /* Not acceptable, reject it */ 41891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto reject_it; 41901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req) { /* Was a request, send response. */ 41911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->nego_status = NS_PPR; 41921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL_DSP(np, SCRIPTB_BA(np, ppr_resp)); 41931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 41941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else /* Was a response, we are done. */ 41951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL_DSP(np, SCRIPTA_BA(np, clrack)); 41961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 41971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreject_it: 41991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL_DSP(np, SCRIPTB_BA(np, msg_bad)); 42001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 42011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 42031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * chip handler for WIDE DATA TRANSFER REQUEST (WDTR) message. 42041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 42051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 42061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldssym_wide_nego_check(struct sym_hcb *np, int req, struct sym_ccb *cp) 42071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 42081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int target = cp->target; 42091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char chg, wide; 42101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (DEBUG_FLAGS & DEBUG_NEGO) { 42121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_print_nego_msg(np, target, "wide msgin", np->msgin); 42131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 42141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 42161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get requested values. 42171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 42181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds chg = 0; 42191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wide = np->msgin[3]; 42201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 42221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Check values against our limits. 42231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 42241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (wide > np->maxwide) { 42251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds chg = 1; 42261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wide = np->maxwide; 42271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 42281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (DEBUG_FLAGS & DEBUG_NEGO) { 42301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_print_addr(cp->cmd, "wdtr: wide=%d chg=%d.\n", 42311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds wide, chg); 42321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 42331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 42351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If it was an answer we want to change, 42361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * then it isn't acceptable. Reject it. 42371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 42381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!req && chg) 42391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto reject_it; 42401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 42421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Apply new values. 42431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 42441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_setwide (np, target, wide); 42451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 42471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * It was an answer. We are done. 42481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 42491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!req) 42501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 42511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 42531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * It was a request. Prepare an answer message. 42541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 42556ea3c0b2dac0d6a857d6bc010e544f4c901fff78Matthew Wilcox spi_populate_width_msg(np->msgout, wide); 42561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->msgin [0] = M_NOOP; 42581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (DEBUG_FLAGS & DEBUG_NEGO) { 42601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_print_nego_msg(np, target, "wide msgout", np->msgout); 42611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 42621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 42641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreject_it: 42661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 42671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 42681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sym_wide_nego(struct sym_hcb *np, struct sym_tcb *tp, struct sym_ccb *cp) 42701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 42711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int req = 1; 42721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int result; 42731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 42751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Request or answer ? 42761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 42771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (INB(np, HS_PRT) == HS_NEGOTIATE) { 42781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, HS_PRT, HS_BUSY); 42791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp->nego_status && cp->nego_status != NS_WIDE) 42801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto reject_it; 42811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds req = 0; 42821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 42831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 42841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 42851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Check and apply new values. 42861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 42871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds result = sym_wide_nego_check(np, req, cp); 42881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (result) /* Not acceptable, reject it */ 42891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto reject_it; 42901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (req) { /* Was a request, send response. */ 42911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->nego_status = NS_WIDE; 42921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL_DSP(np, SCRIPTB_BA(np, wdtr_resp)); 42931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { /* Was a response. */ 42941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 42951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Negotiate for SYNC immediately after WIDE response. 42961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This allows to negotiate for both WIDE and SYNC on 42971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a single SCSI command (Suggested by Justin Gibbs). 42981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 42991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tp->tgoal.offset) { 43006ea3c0b2dac0d6a857d6bc010e544f4c901fff78Matthew Wilcox spi_populate_sync_msg(np->msgout, tp->tgoal.period, 43016ea3c0b2dac0d6a857d6bc010e544f4c901fff78Matthew Wilcox tp->tgoal.offset); 43021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (DEBUG_FLAGS & DEBUG_NEGO) { 43041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_print_nego_msg(np, cp->target, 43051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "sync msgout", np->msgout); 43061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 43071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->nego_status = NS_SYNC; 43091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, HS_PRT, HS_NEGOTIATE); 43101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL_DSP(np, SCRIPTB_BA(np, sdtr_resp)); 43111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 43121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else 43131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL_DSP(np, SCRIPTA_BA(np, clrack)); 43141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 43151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 43171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsreject_it: 43191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL_DSP(np, SCRIPTB_BA(np, msg_bad)); 43201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 43211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 43231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Reset DT, SYNC or WIDE to default settings. 43241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 43251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Called when a negotiation does not succeed either 43261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * on rejection or on protocol error. 43271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 43281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A target that understands a PPR message should never 43291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * reject it, and messing with it is very unlikely. 43301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * So, if a PPR makes problems, we may just want to 43311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * try a legacy negotiation later. 43321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 43331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sym_nego_default(struct sym_hcb *np, struct sym_tcb *tp, struct sym_ccb *cp) 43341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 43351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (cp->nego_status) { 43361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case NS_PPR: 43371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 43381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_setpprot (np, cp->target, 0, 0, 0, 0, 0, 0); 43391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 43401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tp->tgoal.period < np->minsync) 43411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->tgoal.period = np->minsync; 43421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tp->tgoal.offset > np->maxoffs) 43431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->tgoal.offset = np->maxoffs; 43441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->tgoal.iu = tp->tgoal.dt = tp->tgoal.qas = 0; 43451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->tgoal.check_nego = 1; 43461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 43471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 43481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case NS_SYNC: 43491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_setsync (np, cp->target, 0, 0, 0, 0); 43501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 43511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case NS_WIDE: 43521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_setwide (np, cp->target, 0); 43531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 43541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 43551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->msgin [0] = M_NOOP; 43561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->msgout[0] = M_NOOP; 43571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->nego_status = 0; 43581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 43591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 43611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * chip handler for MESSAGE REJECT received in response to 43621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * PPR, WIDE or SYNCHRONOUS negotiation. 43631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 43641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sym_nego_rejected(struct sym_hcb *np, struct sym_tcb *tp, struct sym_ccb *cp) 43651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 43661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_nego_default(np, tp, cp); 43671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, HS_PRT, HS_BUSY); 43681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 43691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 43711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * chip exception handler for programmed interrupts. 43721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 43733fb364e089e05c35ead55a08d56d3004193681f6Matthew Wilcoxstatic void sym_int_sir(struct sym_hcb *np) 43741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 43751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char num = INB(np, nc_dsps); 43761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u32 dsa = INL(np, nc_dsa); 43771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_ccb *cp = sym_ccb_from_dsa(np, dsa); 43781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char target = INB(np, nc_sdid) & 0x0f; 43791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_tcb *tp = &np->target[target]; 43801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int tmp; 43811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (DEBUG_FLAGS & DEBUG_TINY) printf ("I#%d", num); 43831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 43841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (num) { 43851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if SYM_CONF_DMA_ADDRESSING_MODE == 2 43861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 43871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SCRIPTS tell us that we may have to update 43881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 64 bit DMA segment registers. 43891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 43901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIR_DMAP_DIRTY: 43911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_update_dmap_regs(np); 43921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 43931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 43941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 43951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Command has been completed with error condition 43961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * or has been auto-sensed. 43971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 43981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIR_COMPLETE_ERROR: 43991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_complete_error(np, cp); 44001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 44011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 44021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The C code is currently trying to recover from something. 44031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Typically, user want to abort some command. 44041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 44051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIR_SCRIPT_STOPPED: 44061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIR_TARGET_SELECTED: 44071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIR_ABORT_SENT: 44081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_sir_task_recovery(np, num); 44091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 44101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 44111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The device didn't go to MSG OUT phase after having 44123fb364e089e05c35ead55a08d56d3004193681f6Matthew Wilcox * been selected with ATN. We do not want to handle that. 44131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 44141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIR_SEL_ATN_NO_MSG_OUT: 44153fb364e089e05c35ead55a08d56d3004193681f6Matthew Wilcox scmd_printk(KERN_WARNING, cp->cmd, 44163fb364e089e05c35ead55a08d56d3004193681f6Matthew Wilcox "No MSG OUT phase after selection with ATN\n"); 44171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_stuck; 44181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 44191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The device didn't switch to MSG IN phase after 44203fb364e089e05c35ead55a08d56d3004193681f6Matthew Wilcox * having reselected the initiator. 44211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 44221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIR_RESEL_NO_MSG_IN: 44233fb364e089e05c35ead55a08d56d3004193681f6Matthew Wilcox scmd_printk(KERN_WARNING, cp->cmd, 44243fb364e089e05c35ead55a08d56d3004193681f6Matthew Wilcox "No MSG IN phase after reselection\n"); 44251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_stuck; 44261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 44271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * After reselection, the device sent a message that wasn't 44281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * an IDENTIFY. 44291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 44301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIR_RESEL_NO_IDENTIFY: 44313fb364e089e05c35ead55a08d56d3004193681f6Matthew Wilcox scmd_printk(KERN_WARNING, cp->cmd, 44323fb364e089e05c35ead55a08d56d3004193681f6Matthew Wilcox "No IDENTIFY after reselection\n"); 44331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_stuck; 44341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 44353fb364e089e05c35ead55a08d56d3004193681f6Matthew Wilcox * The device reselected a LUN we do not know about. 44361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 44371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIR_RESEL_BAD_LUN: 44381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->msgout[0] = M_RESET; 44391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 44401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 44411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The device reselected for an untagged nexus and we 44421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * haven't any. 44431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 44441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIR_RESEL_BAD_I_T_L: 44451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->msgout[0] = M_ABORT; 44461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 44471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 44483fb364e089e05c35ead55a08d56d3004193681f6Matthew Wilcox * The device reselected for a tagged nexus that we do not have. 44491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 44501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIR_RESEL_BAD_I_T_L_Q: 44511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->msgout[0] = M_ABORT_TAG; 44521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 44531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 44541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The SCRIPTS let us know that the device has grabbed 44551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * our message and will abort the job. 44561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 44571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIR_RESEL_ABORTED: 44581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->lastmsg = np->msgout[0]; 44591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->msgout[0] = M_NOOP; 44603fb364e089e05c35ead55a08d56d3004193681f6Matthew Wilcox scmd_printk(KERN_WARNING, cp->cmd, 44613fb364e089e05c35ead55a08d56d3004193681f6Matthew Wilcox "message %x sent on bad reselection\n", np->lastmsg); 44621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 44631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 44641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The SCRIPTS let us know that a message has been 44651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * successfully sent to the device. 44661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 44671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIR_MSG_OUT_DONE: 44681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->lastmsg = np->msgout[0]; 44691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->msgout[0] = M_NOOP; 44701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Should we really care of that */ 44711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->lastmsg == M_PARITY || np->lastmsg == M_ID_ERROR) { 44721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp) { 44731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->xerr_status &= ~XE_PARITY_ERR; 44741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!cp->xerr_status) 44751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTOFFB(np, HF_PRT, HF_EXT_ERR); 44761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 44771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 44781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 44791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 44801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The device didn't send a GOOD SCSI status. 44811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We may have some work to do prior to allow 44821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the SCRIPTS processor to continue. 44831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 44841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIR_BAD_SCSI_STATUS: 44851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!cp) 44861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 44871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_sir_bad_scsi_status(np, num, cp); 44881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 44891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 44901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We are asked by the SCRIPTS to prepare a 44911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * REJECT message. 44921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 44931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIR_REJECT_TO_SEND: 44941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_print_msg(cp, "M_REJECT to send for ", np->msgin); 44951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->msgout[0] = M_REJECT; 44961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 44971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 44981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We have been ODD at the end of a DATA IN 44991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * transfer and the device didn't send a 45001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * IGNORE WIDE RESIDUE message. 45011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * It is a data overrun condition. 45021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 45031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIR_SWIDE_OVERRUN: 45041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp) { 45051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTONB(np, HF_PRT, HF_EXT_ERR); 45061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->xerr_status |= XE_SWIDE_OVRUN; 45071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 45081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 45091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 45101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We have been ODD at the end of a DATA OUT 45111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * transfer. 45121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * It is a data underrun condition. 45131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 45141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIR_SODL_UNDERRUN: 45151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp) { 45161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTONB(np, HF_PRT, HF_EXT_ERR); 45171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->xerr_status |= XE_SODL_UNRUN; 45181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 45191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 45201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 45211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The device wants us to tranfer more data than 45221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * expected or in the wrong direction. 45231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The number of extra bytes is in scratcha. 45241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * It is a data overrun condition. 45251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 45261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIR_DATA_OVERRUN: 45271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp) { 45281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTONB(np, HF_PRT, HF_EXT_ERR); 45291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->xerr_status |= XE_EXTRA_DATA; 45301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->extra_bytes += INL(np, nc_scratcha); 45311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 45321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 45331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 45341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The device switched to an illegal phase (4/5). 45351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 45361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIR_BAD_PHASE: 45371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp) { 45381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTONB(np, HF_PRT, HF_EXT_ERR); 45391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->xerr_status |= XE_BAD_PHASE; 45401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 45411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 45421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 45431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We received a message. 45441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 45451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIR_MSG_RECEIVED: 45461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!cp) 45471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_stuck; 45481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (np->msgin [0]) { 45491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 45501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We received an extended message. 45511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We handle MODIFY DATA POINTER, SDTR, WDTR 45521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and reject all other extended messages. 45531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 45541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case M_EXTENDED: 45551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch (np->msgin [2]) { 45561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case M_X_MODIFY_DP: 45571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (DEBUG_FLAGS & DEBUG_POINTER) 45582e4c332913b5d39fef686b3964098f0d8fd97eadDavid Miller sym_print_msg(cp, "extended msg ", 45592e4c332913b5d39fef686b3964098f0d8fd97eadDavid Miller np->msgin); 45601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tmp = (np->msgin[3]<<24) + (np->msgin[4]<<16) + 45611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (np->msgin[5]<<8) + (np->msgin[6]); 45621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_modify_dp(np, tp, cp, tmp); 45631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 45641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case M_X_SYNC_REQ: 45651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_sync_nego(np, tp, cp); 45661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 45671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case M_X_PPR_REQ: 45681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_ppr_nego(np, tp, cp); 45691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 45701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case M_X_WIDE_REQ: 45711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_wide_nego(np, tp, cp); 45721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 45731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 45741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_reject; 45751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 45761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 45771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 45781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We received a 1/2 byte message not handled from SCRIPTS. 45791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We are only expecting MESSAGE REJECT and IGNORE WIDE 45801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * RESIDUE messages that haven't been anticipated by 45811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SCRIPTS on SWIDE full condition. Unanticipated IGNORE 45821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * WIDE RESIDUE messages are aliased as MODIFY DP (-1). 45831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 45841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case M_IGN_RESIDUE: 45851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (DEBUG_FLAGS & DEBUG_POINTER) 45862e4c332913b5d39fef686b3964098f0d8fd97eadDavid Miller sym_print_msg(cp, "1 or 2 byte ", np->msgin); 45871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp->host_flags & HF_SENSE) 45881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL_DSP(np, SCRIPTA_BA(np, clrack)); 45891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 45901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_modify_dp(np, tp, cp, -1); 45911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 45921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case M_REJECT: 45931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (INB(np, HS_PRT) == HS_NEGOTIATE) 45941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_nego_rejected(np, tp, cp); 45951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 45961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_print_addr(cp->cmd, 45971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "M_REJECT received (%x:%x).\n", 45981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds scr_to_cpu(np->lastmsg), np->msgout[0]); 45991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 46001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_clrack; 46011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 46021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 46031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_reject; 46041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 46051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 46061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 46071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We received an unknown message. 46081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Ignore all MSG IN phases and reject it. 46091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 46101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIR_MSG_WEIRD: 46111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_print_msg(cp, "WEIRD message received", np->msgin); 46121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL_DSP(np, SCRIPTB_BA(np, msg_weird)); 46131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 46141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 46151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Negotiation failed. 46161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Target does not send us the reply. 46171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Remove the HS_NEGOTIATE status. 46181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 46191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIR_NEGO_FAILED: 46201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, HS_PRT, HS_BUSY); 46211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 46221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Negotiation failed. 46231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Target does not want answer message. 46241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 46251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case SIR_NEGO_PROTO: 46261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_nego_default(np, tp, cp); 46271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 46281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 46291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 46301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 46311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTONB_STD(); 46321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 46331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_reject: 46341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL_DSP(np, SCRIPTB_BA(np, msg_bad)); 46351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 46361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_clrack: 46371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL_DSP(np, SCRIPTA_BA(np, clrack)); 46381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 46391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_stuck: 46401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 46411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 46421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 46431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 46441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Acquire a control block 46451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 46461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct sym_ccb *sym_get_ccb (struct sym_hcb *np, struct scsi_cmnd *cmd, u_char tag_order) 46471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 46481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char tn = cmd->device->id; 46491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char ln = cmd->device->lun; 46501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_tcb *tp = &np->target[tn]; 46511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_lcb *lp = sym_lp(tp, ln); 46521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_short tag = NO_TAG; 46531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SYM_QUEHEAD *qp; 46541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_ccb *cp = NULL; 46551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 46561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 46571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Look for a free CCB 46581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 46591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sym_que_empty(&np->free_ccbq)) 46601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_alloc_ccb(np); 46611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds qp = sym_remque_head(&np->free_ccbq); 46621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!qp) 46631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out; 46641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); 46651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 466684e203a279d3de1c8a41a73ab45e55a89bc19345Matthew Wilcox { 46671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 46681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we have been asked for a tagged command. 46691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 46701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (tag_order) { 46711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 46721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Debugging purpose. 46731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 46741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef SYM_OPT_HANDLE_DEVICE_QUEUEING 46753bea15a76eecc03729bf74d6ab2a1f849c08423eMatthew Wilcox if (lp->busy_itl != 0) 46763bea15a76eecc03729bf74d6ab2a1f849c08423eMatthew Wilcox goto out_free; 46771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 46781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 46791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Allocate resources for tags if not yet. 46801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 46811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!lp->cb_tags) { 46821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_alloc_lcb_tags(np, tn, ln); 46831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!lp->cb_tags) 46841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_free; 46851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 46861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 46871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get a tag for this SCSI IO and set up 46881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the CCB bus address for reselection, 46891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and count it for this LUN. 46901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Toggle reselect path to tagged. 46911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 46921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lp->busy_itlq < SYM_CONF_MAX_TASK) { 46931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tag = lp->cb_tags[lp->ia_tag]; 46941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (++lp->ia_tag == SYM_CONF_MAX_TASK) 46951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->ia_tag = 0; 46961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ++lp->busy_itlq; 46971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef SYM_OPT_HANDLE_DEVICE_QUEUEING 46981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->itlq_tbl[tag] = cpu_to_scr(cp->ccb_ba); 46991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->head.resel_sa = 47001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cpu_to_scr(SCRIPTA_BA(np, resel_tag)); 47011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 47021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef SYM_OPT_LIMIT_COMMAND_REORDERING 47031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->tags_si = lp->tags_si; 47041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ++lp->tags_sum[cp->tags_si]; 47051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ++lp->tags_since; 47061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 47071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 47081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 47091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_free; 47101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 47111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 47121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This command will not be tagged. 47131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we already have either a tagged or untagged 47141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * one, refuse to overlap this untagged one. 47151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 47161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 47171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 47181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Debugging purpose. 47191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 47201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef SYM_OPT_HANDLE_DEVICE_QUEUEING 47213bea15a76eecc03729bf74d6ab2a1f849c08423eMatthew Wilcox if (lp->busy_itl != 0 || lp->busy_itlq != 0) 47223bea15a76eecc03729bf74d6ab2a1f849c08423eMatthew Wilcox goto out_free; 47231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 47241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 47251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Count this nexus for this LUN. 47261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set up the CCB bus address for reselection. 47271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Toggle reselect path to untagged. 47281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 47291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ++lp->busy_itl; 47301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifndef SYM_OPT_HANDLE_DEVICE_QUEUEING 47311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lp->busy_itl == 1) { 47321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->head.itl_task_sa = cpu_to_scr(cp->ccb_ba); 47331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->head.resel_sa = 47341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cpu_to_scr(SCRIPTA_BA(np, resel_no_tag)); 47351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 47361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 47371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_free; 47381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 47391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 47401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 47411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 47421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Put the CCB into the busy queue. 47431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 47441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_insque_tail(&cp->link_ccbq, &np->busy_ccbq); 47451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING 47461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lp) { 47471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_remque(&cp->link2_ccbq); 47481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_insque_tail(&cp->link2_ccbq, &lp->waiting_ccbq); 47491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 47501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 47511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 47521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->to_abort = 0; 475353222b906903fd861dc24ebccfa07ee125941313Matthew Wilcox cp->odd_byte_adjustment = 0; 47541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->tag = tag; 47551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->order = tag_order; 47561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->target = tn; 47571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->lun = ln; 47581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 47591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (DEBUG_FLAGS & DEBUG_TAGS) { 47601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_print_addr(cmd, "ccb @%p using tag %d.\n", cp, tag); 47611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 47621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 47631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout: 47641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return cp; 47651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_free: 47661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_insque_head(&cp->link_ccbq, &np->free_ccbq); 47671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 47681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 47691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 47701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 47711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Release one control block 47721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 47731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid sym_free_ccb (struct sym_hcb *np, struct sym_ccb *cp) 47741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 47751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_tcb *tp = &np->target[cp->target]; 47761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_lcb *lp = sym_lp(tp, cp->lun); 47771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 47781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (DEBUG_FLAGS & DEBUG_TAGS) { 47791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_print_addr(cp->cmd, "ccb @%p freeing tag %d.\n", 47801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp, cp->tag); 47811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 47821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 47831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 47841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If LCB available, 47851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 47861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lp) { 47871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 47881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If tagged, release the tag, set the relect path 47891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 47901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp->tag != NO_TAG) { 47911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef SYM_OPT_LIMIT_COMMAND_REORDERING 47921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds --lp->tags_sum[cp->tags_si]; 47931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 47941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 47951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Free the tag value. 47961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 47971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->cb_tags[lp->if_tag] = cp->tag; 47981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (++lp->if_tag == SYM_CONF_MAX_TASK) 47991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->if_tag = 0; 48001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 48011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Make the reselect path invalid, 48021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and uncount this CCB. 48031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 48041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->itlq_tbl[cp->tag] = cpu_to_scr(np->bad_itlq_ba); 48051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds --lp->busy_itlq; 48061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { /* Untagged */ 48071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 48081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Make the reselect path invalid, 48091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and uncount this CCB. 48101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 48111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->head.itl_task_sa = cpu_to_scr(np->bad_itl_ba); 48121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds --lp->busy_itl; 48131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 48141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 48151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If no JOB active, make the LUN reselect path invalid. 48161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 48171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lp->busy_itlq == 0 && lp->busy_itl == 0) 48181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->head.resel_sa = 48191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cpu_to_scr(SCRIPTB_BA(np, resel_bad_lun)); 48201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 48211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 48221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 48231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We donnot queue more than 1 ccb per target 48241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * with negotiation at any time. If this ccb was 48251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * used for negotiation, clear this info in the tcb. 48261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 48271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp == tp->nego_cp) 48281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->nego_cp = NULL; 48291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 48301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef SYM_CONF_IARB_SUPPORT 48311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 48321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If we just complete the last queued CCB, 48331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * clear this info that is no longer relevant. 48341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 48351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp == np->last_cp) 48361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->last_cp = 0; 48371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 48381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 48391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 48401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Make this CCB available. 48411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 48421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->cmd = NULL; 48431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->host_status = HS_IDLE; 48441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_remque(&cp->link_ccbq); 48451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_insque_head(&cp->link_ccbq, &np->free_ccbq); 48461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 48471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING 48481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lp) { 48491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_remque(&cp->link2_ccbq); 48501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_insque_tail(&cp->link2_ccbq, &np->dummy_ccbq); 48511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp->started) { 48521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp->tag != NO_TAG) 48531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds --lp->started_tags; 48541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 48551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds --lp->started_no_tag; 48561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 48571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 48581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->started = 0; 48591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 48601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 48611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 48621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 48631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Allocate a CCB from memory and initialize its fixed part. 48641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 48651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sym_ccb *sym_alloc_ccb(struct sym_hcb *np) 48661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 48671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_ccb *cp = NULL; 48681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int hcode; 48691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 48701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 48711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Prevent from allocating more CCBs than we can 48721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * queue to the controller. 48731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 48741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->actccbs >= SYM_CONF_MAX_START) 48751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 48761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 48771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 48781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Allocate memory for this CCB. 48791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 48801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp = sym_calloc_dma(sizeof(struct sym_ccb), "CCB"); 48811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!cp) 48821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto out_free; 48831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 48841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 48851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Count it. 48861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 48871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->actccbs++; 48881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 48891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 48901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Compute the bus address of this ccb. 48911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 48921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->ccb_ba = vtobus(cp); 48931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 48941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 48951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Insert this ccb into the hashed list. 48961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 48971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hcode = CCB_HASH_CODE(cp->ccb_ba); 48981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->link_ccbh = np->ccbh[hcode]; 48991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->ccbh[hcode] = cp; 49001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 49011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 49021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Initialyze the start and restart actions. 49031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 49041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->phys.head.go.start = cpu_to_scr(SCRIPTA_BA(np, idle)); 49051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->phys.head.go.restart = cpu_to_scr(SCRIPTB_BA(np, bad_i_t_l)); 49061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 49071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 49081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Initilialyze some other fields. 49091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 49101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->phys.smsg_ext.addr = cpu_to_scr(HCB_BA(np, msgin[2])); 49111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 49121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 49131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Chain into free ccb queue. 49141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 49151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_insque_head(&cp->link_ccbq, &np->free_ccbq); 49161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 49171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 49181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Chain into optionnal lists. 49191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 49201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING 49211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_insque_head(&cp->link2_ccbq, &np->dummy_ccbq); 49221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 49231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return cp; 49241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsout_free: 49251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp) 49261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_mfree_dma(cp, sizeof(*cp), "CCB"); 49271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return NULL; 49281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 49291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 49301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 49311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Look up a CCB from a DSA value. 49321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 49331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct sym_ccb *sym_ccb_from_dsa(struct sym_hcb *np, u32 dsa) 49341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 49351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int hcode; 49361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_ccb *cp; 49371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 49381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds hcode = CCB_HASH_CODE(dsa); 49391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp = np->ccbh[hcode]; 49401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds while (cp) { 49411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp->ccb_ba == dsa) 49421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 49431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp = cp->link_ccbh; 49441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 49451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 49461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return cp; 49471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 49481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 49491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 49501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Target control block initialisation. 49511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Nothing important to do at the moment. 49521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 49531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sym_init_tcb (struct sym_hcb *np, u_char tn) 49541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 49551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 /* Hmmm... this checking looks paranoid. */ 49561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 49571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Check some alignments required by the chip. 49581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 49591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds assert (((offsetof(struct sym_reg, nc_sxfer) ^ 49601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offsetof(struct sym_tcb, head.sval)) &3) == 0); 49611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds assert (((offsetof(struct sym_reg, nc_scntl3) ^ 49621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds offsetof(struct sym_tcb, head.wval)) &3) == 0); 49631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 49641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 49651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 49661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 49671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Lun control block allocation and initialization. 49681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 49691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct sym_lcb *sym_alloc_lcb (struct sym_hcb *np, u_char tn, u_char ln) 49701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 49711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_tcb *tp = &np->target[tn]; 497284e203a279d3de1c8a41a73ab45e55a89bc19345Matthew Wilcox struct sym_lcb *lp = NULL; 49731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 49741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 49751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Initialize the target control block if not yet. 49761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 49771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_init_tcb (np, tn); 49781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 49791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 49801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Allocate the LCB bus address array. 49811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Compute the bus address of this table. 49821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 49831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ln && !tp->luntbl) { 49841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 49851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 49861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->luntbl = sym_calloc_dma(256, "LUNTBL"); 49871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!tp->luntbl) 49881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto fail; 49891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0 ; i < 64 ; i++) 49901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->luntbl[i] = cpu_to_scr(vtobus(&np->badlun_sa)); 49911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->head.luntbl_sa = cpu_to_scr(vtobus(tp->luntbl)); 49921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 49931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 49941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 49951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Allocate the table of pointers for LUN(s) > 0, if needed. 49961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 49971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ln && !tp->lunmp) { 49981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->lunmp = kcalloc(SYM_CONF_MAX_LUN, sizeof(struct sym_lcb *), 4999fa8584566cc9cdaf067dbc12132792887a521da9Aaro Koskinen GFP_ATOMIC); 50001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!tp->lunmp) 50011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto fail; 50021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 50031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 50041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 50051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Allocate the lcb. 50061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Make it available to the chip. 50071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 50081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp = sym_calloc_dma(sizeof(struct sym_lcb), "LCB"); 50091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!lp) 50101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto fail; 50111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (ln) { 50121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->lunmp[ln] = lp; 50131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->luntbl[ln] = cpu_to_scr(vtobus(lp)); 50141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 50151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else { 50161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->lun0p = lp; 50171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->head.lun0_sa = cpu_to_scr(vtobus(lp)); 50181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5019fa8584566cc9cdaf067dbc12132792887a521da9Aaro Koskinen tp->nlcb++; 50201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 50211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 50221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Let the itl task point to error handling. 50231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 50241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->head.itl_task_sa = cpu_to_scr(np->bad_itl_ba); 50251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 50261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 50271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set the reselect pattern to our default. :) 50281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 50291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->head.resel_sa = cpu_to_scr(SCRIPTB_BA(np, resel_bad_lun)); 50301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 50311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 50321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Set user capabilities. 50331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 50341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->user_flags = tp->usrflags & (SYM_DISC_ENABLED | SYM_TAGS_ENABLED); 50351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 50361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING 50371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 50381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Initialize device queueing. 50391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 50401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_que_init(&lp->waiting_ccbq); 50411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_que_init(&lp->started_ccbq); 50421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->started_max = SYM_CONF_MAX_TASK; 50431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->started_limit = SYM_CONF_MAX_TASK; 50441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 504584e203a279d3de1c8a41a73ab45e55a89bc19345Matthew Wilcox 50461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfail: 50471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return lp; 50481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 50491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 50501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 50511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Allocate LCB resources for tagged command queuing. 50521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 50531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void sym_alloc_lcb_tags (struct sym_hcb *np, u_char tn, u_char ln) 50541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 50551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_tcb *tp = &np->target[tn]; 50561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_lcb *lp = sym_lp(tp, ln); 50571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 50581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 50591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 50601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Allocate the task table and and the tag allocation 50611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * circular buffer. We want both or none. 50621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 50631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->itlq_tbl = sym_calloc_dma(SYM_CONF_MAX_TASK*4, "ITLQ_TBL"); 50641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!lp->itlq_tbl) 50651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto fail; 506653222b906903fd861dc24ebccfa07ee125941313Matthew Wilcox lp->cb_tags = kcalloc(SYM_CONF_MAX_TASK, 1, GFP_ATOMIC); 50671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!lp->cb_tags) { 50681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_mfree_dma(lp->itlq_tbl, SYM_CONF_MAX_TASK*4, "ITLQ_TBL"); 50691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->itlq_tbl = NULL; 50701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto fail; 50711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 50721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 50731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 50741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Initialize the task table with invalid entries. 50751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 50761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0 ; i < SYM_CONF_MAX_TASK ; i++) 50771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->itlq_tbl[i] = cpu_to_scr(np->notask_ba); 50781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 50791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 50801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Fill up the tag buffer with tag numbers. 50811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 50821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0 ; i < SYM_CONF_MAX_TASK ; i++) 50831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->cb_tags[i] = i; 50841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 50851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 50861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Make the task table available to SCRIPTS, 50871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * And accept tagged commands now. 50881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 50891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->head.itlq_tbl_sa = cpu_to_scr(vtobus(lp->itlq_tbl)); 50901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 50911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 50921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfail: 50931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 50941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 50951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 50961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 509725985edcedea6396277003854657b5f3cb31a628Lucas De Marchi * Lun control block deallocation. Returns the number of valid remaining LCBs 5098fa8584566cc9cdaf067dbc12132792887a521da9Aaro Koskinen * for the target. 5099fa8584566cc9cdaf067dbc12132792887a521da9Aaro Koskinen */ 5100fa8584566cc9cdaf067dbc12132792887a521da9Aaro Koskinenint sym_free_lcb(struct sym_hcb *np, u_char tn, u_char ln) 5101fa8584566cc9cdaf067dbc12132792887a521da9Aaro Koskinen{ 5102fa8584566cc9cdaf067dbc12132792887a521da9Aaro Koskinen struct sym_tcb *tp = &np->target[tn]; 5103fa8584566cc9cdaf067dbc12132792887a521da9Aaro Koskinen struct sym_lcb *lp = sym_lp(tp, ln); 5104fa8584566cc9cdaf067dbc12132792887a521da9Aaro Koskinen 5105fa8584566cc9cdaf067dbc12132792887a521da9Aaro Koskinen tp->nlcb--; 5106fa8584566cc9cdaf067dbc12132792887a521da9Aaro Koskinen 5107fa8584566cc9cdaf067dbc12132792887a521da9Aaro Koskinen if (ln) { 5108fa8584566cc9cdaf067dbc12132792887a521da9Aaro Koskinen if (!tp->nlcb) { 5109fa8584566cc9cdaf067dbc12132792887a521da9Aaro Koskinen kfree(tp->lunmp); 5110fa8584566cc9cdaf067dbc12132792887a521da9Aaro Koskinen sym_mfree_dma(tp->luntbl, 256, "LUNTBL"); 5111fa8584566cc9cdaf067dbc12132792887a521da9Aaro Koskinen tp->lunmp = NULL; 5112fa8584566cc9cdaf067dbc12132792887a521da9Aaro Koskinen tp->luntbl = NULL; 5113fa8584566cc9cdaf067dbc12132792887a521da9Aaro Koskinen tp->head.luntbl_sa = cpu_to_scr(vtobus(np->badluntbl)); 5114fa8584566cc9cdaf067dbc12132792887a521da9Aaro Koskinen } else { 5115fa8584566cc9cdaf067dbc12132792887a521da9Aaro Koskinen tp->luntbl[ln] = cpu_to_scr(vtobus(&np->badlun_sa)); 5116fa8584566cc9cdaf067dbc12132792887a521da9Aaro Koskinen tp->lunmp[ln] = NULL; 5117fa8584566cc9cdaf067dbc12132792887a521da9Aaro Koskinen } 5118fa8584566cc9cdaf067dbc12132792887a521da9Aaro Koskinen } else { 5119fa8584566cc9cdaf067dbc12132792887a521da9Aaro Koskinen tp->lun0p = NULL; 5120fa8584566cc9cdaf067dbc12132792887a521da9Aaro Koskinen tp->head.lun0_sa = cpu_to_scr(vtobus(&np->badlun_sa)); 5121fa8584566cc9cdaf067dbc12132792887a521da9Aaro Koskinen } 5122fa8584566cc9cdaf067dbc12132792887a521da9Aaro Koskinen 5123fa8584566cc9cdaf067dbc12132792887a521da9Aaro Koskinen if (lp->itlq_tbl) { 5124fa8584566cc9cdaf067dbc12132792887a521da9Aaro Koskinen sym_mfree_dma(lp->itlq_tbl, SYM_CONF_MAX_TASK*4, "ITLQ_TBL"); 5125fa8584566cc9cdaf067dbc12132792887a521da9Aaro Koskinen kfree(lp->cb_tags); 5126fa8584566cc9cdaf067dbc12132792887a521da9Aaro Koskinen } 5127fa8584566cc9cdaf067dbc12132792887a521da9Aaro Koskinen 5128fa8584566cc9cdaf067dbc12132792887a521da9Aaro Koskinen sym_mfree_dma(lp, sizeof(*lp), "LCB"); 5129fa8584566cc9cdaf067dbc12132792887a521da9Aaro Koskinen 5130fa8584566cc9cdaf067dbc12132792887a521da9Aaro Koskinen return tp->nlcb; 5131fa8584566cc9cdaf067dbc12132792887a521da9Aaro Koskinen} 5132fa8584566cc9cdaf067dbc12132792887a521da9Aaro Koskinen 5133fa8584566cc9cdaf067dbc12132792887a521da9Aaro Koskinen/* 51341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Queue a SCSI IO to the controller. 51351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 51361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint sym_queue_scsiio(struct sym_hcb *np, struct scsi_cmnd *cmd, struct sym_ccb *cp) 51371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 51381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scsi_device *sdev = cmd->device; 51391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_tcb *tp; 51401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_lcb *lp; 51411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char *msgptr; 51421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_int msglen; 51431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int can_disconnect; 51441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 51451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 51461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Keep track of the IO in our CCB. 51471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 51481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->cmd = cmd; 51491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 51501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 51511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Retrieve the target descriptor. 51521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 51531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp = &np->target[cp->target]; 51541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 51551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 51561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Retrieve the lun descriptor. 51571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 51581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp = sym_lp(tp, sdev->lun); 51591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 51601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds can_disconnect = (cp->tag != NO_TAG) || 51611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds (lp && (lp->curr_flags & SYM_DISC_ENABLED)); 51621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 51631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msgptr = cp->scsi_smsg; 51641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msglen = 0; 51651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msgptr[msglen++] = IDENTIFY(can_disconnect, sdev->lun); 51661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 51671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 51681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Build the tag message if present. 51691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 51701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp->tag != NO_TAG) { 51711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds u_char order = cp->order; 51721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 51731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds switch(order) { 51741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case M_ORDERED_TAG: 51751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 51761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds case M_HEAD_TAG: 51771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 51781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds default: 51791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds order = M_SIMPLE_TAG; 51801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 51811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef SYM_OPT_LIMIT_COMMAND_REORDERING 51821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 51831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Avoid too much reordering of SCSI commands. 51841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The algorithm tries to prevent completion of any 51851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * tagged command from being delayed against more 51861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * than 3 times the max number of queued commands. 51871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 51881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lp && lp->tags_since > 3*SYM_CONF_MAX_TAG) { 51891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->tags_si = !(lp->tags_si); 51901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lp->tags_sum[lp->tags_si]) { 51911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds order = M_ORDERED_TAG; 51921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if ((DEBUG_FLAGS & DEBUG_TAGS)||sym_verbose>1) { 51931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_print_addr(cmd, 51941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds "ordered tag forced.\n"); 51951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 51961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 51971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->tags_since = 0; 51981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 51991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 52001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msgptr[msglen++] = order; 52011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 52021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 52031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For less than 128 tags, actual tags are numbered 52041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 1,3,5,..2*MAXTAGS+1,since we may have to deal 52051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * with devices that have problems with #TAG 0 or too 52061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * great #TAG numbers. For more tags (up to 256), 52071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * we use directly our tag number. 52081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 52091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if SYM_CONF_MAX_TASK > (512/4) 52101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msgptr[msglen++] = cp->tag; 52111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 52121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msgptr[msglen++] = (cp->tag << 1) + 1; 52131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 52141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 52151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 52161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 52171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Build a negotiation message if needed. 52181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (nego_status is filled by sym_prepare_nego()) 521949799fee82b4f78c45b1926be24e45b5cf667083Aaro Koskinen * 522049799fee82b4f78c45b1926be24e45b5cf667083Aaro Koskinen * Always negotiate on INQUIRY and REQUEST SENSE. 522149799fee82b4f78c45b1926be24e45b5cf667083Aaro Koskinen * 52221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 52231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->nego_status = 0; 522449799fee82b4f78c45b1926be24e45b5cf667083Aaro Koskinen if ((tp->tgoal.check_nego || 522549799fee82b4f78c45b1926be24e45b5cf667083Aaro Koskinen cmd->cmnd[0] == INQUIRY || cmd->cmnd[0] == REQUEST_SENSE) && 522649799fee82b4f78c45b1926be24e45b5cf667083Aaro Koskinen !tp->nego_cp && lp) { 52271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds msglen += sym_prepare_nego(np, cp, msgptr + msglen); 52281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 52291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 52301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 52311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Startqueue 52321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 52331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->phys.head.go.start = cpu_to_scr(SCRIPTA_BA(np, select)); 52341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->phys.head.go.restart = cpu_to_scr(SCRIPTA_BA(np, resel_dsa)); 52351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 52361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 52371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * select 52381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 52391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->phys.select.sel_id = cp->target; 52401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->phys.select.sel_scntl3 = tp->head.wval; 52411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->phys.select.sel_sxfer = tp->head.sval; 52421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->phys.select.sel_scntl4 = tp->head.uval; 52431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 52441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 52451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * message 52461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 524753222b906903fd861dc24ebccfa07ee125941313Matthew Wilcox cp->phys.smsg.addr = CCB_BA(cp, scsi_smsg); 52481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->phys.smsg.size = cpu_to_scr(msglen); 52491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 52501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 52511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * status 52521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 52531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->host_xflags = 0; 52541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->host_status = cp->nego_status ? HS_NEGOTIATE : HS_BUSY; 52551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->ssss_status = S_ILLEGAL; 52561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->xerr_status = 0; 52571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->host_flags = 0; 52581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->extra_bytes = 0; 52591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 52601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 52611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * extreme data pointer. 52621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * shall be positive, so -1 is lower than lowest.:) 52631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 52641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->ext_sg = -1; 52651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->ext_ofs = 0; 52661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 52671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 52681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Build the CDB and DATA descriptor block 52691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and start the IO. 52701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 52711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sym_setup_data_and_start(np, cmd, cp); 52721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 52731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 52741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 52751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Reset a SCSI target (all LUNs of this target). 52761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 52771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint sym_reset_scsi_target(struct sym_hcb *np, int target) 52781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 52791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_tcb *tp; 52801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 52811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (target == np->myaddr || (u_int)target >= SYM_CONF_MAX_TARGET) 52821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 52831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 52841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp = &np->target[target]; 52851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp->to_reset = 1; 52861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 52871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->istat_sem = SEM; 52881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_istat, SIGP|SEM); 52891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 52901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 52911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 52921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 52931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 52941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Abort a SCSI IO. 52951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 52961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int sym_abort_ccb(struct sym_hcb *np, struct sym_ccb *cp, int timed_out) 52971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 52981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 52991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Check that the IO is active. 53001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 53011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!cp || !cp->host_status || cp->host_status == HS_WAIT) 53021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -1; 53031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 53041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 53051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If a previous abort didn't succeed in time, 53061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * perform a BUS reset. 53071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 53081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp->to_abort) { 53091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_reset_scsi_bus(np, 1); 53101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 53111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 53121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 53131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 53141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Mark the CCB for abort and allow time for. 53151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 53161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->to_abort = timed_out ? 2 : 1; 53171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 53181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 53191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Tell the SCRIPTS processor to stop and synchronize with us. 53201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 53211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->istat_sem = SEM; 53221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTB(np, nc_istat, SIGP|SEM); 53231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 53241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 53251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 53261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint sym_abort_scsiio(struct sym_hcb *np, struct scsi_cmnd *cmd, int timed_out) 53271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 53281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_ccb *cp; 53291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SYM_QUEHEAD *qp; 53301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 53311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 53321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Look up our CCB control block. 53331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 53341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp = NULL; 53351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) { 53361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_ccb *cp2 = sym_que_entry(qp, struct sym_ccb, link_ccbq); 53371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp2->cmd == cmd) { 53381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp = cp2; 53391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds break; 53401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 53411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 53421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 53431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return sym_abort_ccb(np, cp, timed_out); 53441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 53451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 53461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 534753222b906903fd861dc24ebccfa07ee125941313Matthew Wilcox * Complete execution of a SCSI command with extended 53481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * error, SCSI status error, or having been auto-sensed. 53491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 53501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The SCRIPTS processor is not running there, so we 53511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * can safely access IO registers and remove JOBs from 53521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the START queue. 53531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SCRATCHA is assumed to have been loaded with STARTPOS 53541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * before the SCRIPTS called the C code. 53551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 53561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid sym_complete_error(struct sym_hcb *np, struct sym_ccb *cp) 53571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 53581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scsi_device *sdev; 53591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scsi_cmnd *cmd; 53601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_tcb *tp; 53611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_lcb *lp; 53621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int resid; 53631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 53641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 53651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 53661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Paranoid check. :) 53671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 53681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!cp || !cp->cmd) 53691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 53701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 53711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd = cp->cmd; 53721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sdev = cmd->device; 53731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_RESULT)) { 53741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_info(&sdev->sdev_gendev, "CCB=%p STAT=%x/%x/%x\n", cp, 53751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->host_status, cp->ssss_status, cp->host_flags); 53761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 53771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 53781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 53791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get target and lun pointers. 53801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 53811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp = &np->target[cp->target]; 53821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp = sym_lp(tp, sdev->lun); 53831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 53841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 53851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Check for extended errors. 53861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 53871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp->xerr_status) { 53881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sym_verbose) 53891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_print_xerr(cmd, cp->xerr_status); 53901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp->host_status == HS_COMPLETE) 53911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->host_status = HS_COMP_ERR; 53921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 53931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 53941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 53951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Calculate the residual. 53961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 53971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds resid = sym_compute_residual(np, cp); 53981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 53991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!SYM_SETUP_RESIDUAL_SUPPORT) {/* If user does not want residuals */ 54001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds resid = 0; /* throw them away. :) */ 54011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->sv_resid = 0; 54021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 54031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG_2_0_X 54041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsif (resid) 54051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf("XXXX RESID= %d - 0x%x\n", resid, resid); 54061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 54071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 54081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 54091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Dequeue all queued CCBs for that device 54101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * not yet started by SCRIPTS. 54111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 54121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = (INL(np, nc_scratcha) - np->squeue_ba) / 4; 54131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = sym_dequeue_from_squeue(np, i, cp->target, sdev->lun, -1); 54141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 54151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 54161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Restart the SCRIPTS processor. 54171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 54181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds OUTL_DSP(np, SCRIPTA_BA(np, start)); 54191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 54201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING 54211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (cp->host_status == HS_COMPLETE && 54221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->ssss_status == S_QUEUE_FULL) { 54231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!lp || lp->started_tags - i < 2) 54241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto weirdness; 54251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 54261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Decrease queue depth as needed. 54271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 54281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->started_max = lp->started_tags - i - 1; 54291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->num_sgood = 0; 54301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 54311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sym_verbose >= 2) { 54321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_print_addr(cmd, " queue depth is now %d\n", 54331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->started_max); 54341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 54351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 54361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 54371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Repair the CCB. 54381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 54391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->host_status = HS_BUSY; 54401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp->ssss_status = S_ILLEGAL; 54411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 54421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 54431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Let's requeue it to device. 54441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 544553222b906903fd861dc24ebccfa07ee125941313Matthew Wilcox sym_set_cam_status(cmd, DID_SOFT_ERROR); 54461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto finish; 54471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 54481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsweirdness: 54491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 54501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 54511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Build result in CAM ccb. 54521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 54531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_set_cam_result_error(np, cp, resid); 54541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 54551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING 54561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsfinish: 54571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 54581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 54591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Add this one to the COMP queue. 54601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 54611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_remque(&cp->link_ccbq); 54621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_insque_head(&cp->link_ccbq, &np->comp_ccbq); 54631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 54641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 54651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Complete all those commands with either error 54661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * or requeue condition. 54671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 54681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_flush_comp_queue(np, 0); 54691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 54701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING 54711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 54721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Donnot start more than 1 command after an error. 54731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 547484e203a279d3de1c8a41a73ab45e55a89bc19345Matthew Wilcox sym_start_next_ccbs(np, lp, 1); 54751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 54761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 54771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 54781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 54791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Complete execution of a successful SCSI command. 54801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 54811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Only successful commands go to the DONE queue, 54821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * since we need to have the SCRIPTS processor 54831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * stopped on any error condition. 54841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The SCRIPTS processor is running while we are 54851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * completing successful commands. 54861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 54871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid sym_complete_ok (struct sym_hcb *np, struct sym_ccb *cp) 54881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 54891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_tcb *tp; 54901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_lcb *lp; 54911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct scsi_cmnd *cmd; 54921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int resid; 54931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 54941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 54951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Paranoid check. :) 54961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 54971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!cp || !cp->cmd) 54981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return; 54991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds assert (cp->host_status == HS_COMPLETE); 55001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 55011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 55021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get user command. 55031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 55041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cmd = cp->cmd; 55051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 55061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 55071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get target and lun pointers. 55081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 55091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp = &np->target[cp->target]; 55101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp = sym_lp(tp, cp->lun); 55111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 55121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 55131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If all data have been transferred, given than no 55141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * extended error did occur, there is no residual. 55151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 55161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds resid = 0; 551744f30b0f59d628eb6f57cfa9d8ab06da670e5306Matthew Wilcox if (cp->phys.head.lastp != cp->goalp) 55181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds resid = sym_compute_residual(np, cp); 55191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 55201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 55211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Wrong transfer residuals may be worse than just always 55221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * returning zero. User can disable this feature in 55231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * sym53c8xx.h. Residual support is enabled by default. 55241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 55251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!SYM_SETUP_RESIDUAL_SUPPORT) 55261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds resid = 0; 55271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG_2_0_X 55281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsif (resid) 55291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf("XXXX RESID= %d - 0x%x\n", resid, resid); 55301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 55311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 55321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 55331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Build result in CAM ccb. 55341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 55351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_set_cam_result_ok(cp, cmd, resid); 55361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 55371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING 55381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 55391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If max number of started ccbs had been reduced, 55401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * increase it if 200 good status received. 55411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 55421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lp && lp->started_max < lp->started_limit) { 55431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ++lp->num_sgood; 55441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (lp->num_sgood >= 200) { 55451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->num_sgood = 0; 55461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ++lp->started_max; 55471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sym_verbose >= 2) { 55481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_print_addr(cmd, " queue depth is now %d\n", 55491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds lp->started_max); 55501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 55511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 55521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 55531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 55541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 55551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 55561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Free our CCB. 55571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 55581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_free_ccb (np, cp); 55591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 55601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING 55611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 55621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Requeue a couple of awaiting scsi commands. 55631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 556484e203a279d3de1c8a41a73ab45e55a89bc19345Matthew Wilcox if (!sym_que_empty(&lp->waiting_ccbq)) 55651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_start_next_ccbs(np, lp, 2); 55661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 55671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 55681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Complete the command. 55691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 55701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_xpt_done(np, cmd); 55711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 55721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 55731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 55741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Soft-attach the controller. 55751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 55761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint sym_hcb_attach(struct Scsi_Host *shost, struct sym_fw *fw, struct sym_nvram *nvram) 55771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 55781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_hcb *np = sym_get_hcb(shost); 55791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i; 55801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 55811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 55821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Get some info about the firmware. 55831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 55841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->scripta_sz = fw->a_size; 55851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->scriptb_sz = fw->b_size; 55861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->scriptz_sz = fw->z_size; 55871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->fw_setup = fw->setup; 55881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->fw_patch = fw->patch; 55891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->fw_name = fw->name; 55901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 55911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 55921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Save setting of some IO registers, so we will 55931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * be able to probe specific implementations. 55941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 55951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_save_initial_setting (np); 55961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 55971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 55981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Reset the chip now, since it has been reported 55991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that SCSI clock calibration may not work properly 56001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if the chip is currently active. 56011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 56021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_chip_reset(np); 56031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 56041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 56051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Prepare controller and devices settings, according 56061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to chip features, user set-up and driver set-up. 56071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 56081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_prepare_setting(shost, np, nvram); 56091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 56101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 56111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Check the PCI clock frequency. 56121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Must be performed after prepare_setting since it destroys 56131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * STEST1 that is used to probe for the clock doubler. 56141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 56151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds i = sym_getpciclock(np); 56161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (i > 37000 && !(np->features & FE_66MHZ)) 56171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf("%s: PCI BUS clock seems too high: %u KHz.\n", 56181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_name(np), i); 56191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 56201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 56211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Allocate the start queue. 56221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 56231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->squeue = sym_calloc_dma(sizeof(u32)*(MAX_QUEUE*2),"SQUEUE"); 56241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!np->squeue) 56251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto attach_failed; 56261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->squeue_ba = vtobus(np->squeue); 56271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 56281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 56291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Allocate the done queue. 56301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 56311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->dqueue = sym_calloc_dma(sizeof(u32)*(MAX_QUEUE*2),"DQUEUE"); 56321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!np->dqueue) 56331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto attach_failed; 56341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->dqueue_ba = vtobus(np->dqueue); 56351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 56361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 56371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Allocate the target bus address array. 56381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 56391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->targtbl = sym_calloc_dma(256, "TARGTBL"); 56401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!np->targtbl) 56411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto attach_failed; 56421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->targtbl_ba = vtobus(np->targtbl); 56431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 56441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 56451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Allocate SCRIPTS areas. 56461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 56471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->scripta0 = sym_calloc_dma(np->scripta_sz, "SCRIPTA0"); 56481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->scriptb0 = sym_calloc_dma(np->scriptb_sz, "SCRIPTB0"); 56491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->scriptz0 = sym_calloc_dma(np->scriptz_sz, "SCRIPTZ0"); 56501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!np->scripta0 || !np->scriptb0 || !np->scriptz0) 56511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto attach_failed; 56521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 56531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 56541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Allocate the array of lists of CCBs hashed by DSA. 56551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 5656cd86128088554d64fea1679191509f00e6353c5bRobert P. J. Day np->ccbh = kcalloc(CCB_HASH_SIZE, sizeof(struct sym_ccb **), GFP_KERNEL); 56571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!np->ccbh) 56581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto attach_failed; 56591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 56601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 56611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Initialyze the CCB free and busy queues. 56621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 56631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_que_init(&np->free_ccbq); 56641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_que_init(&np->busy_ccbq); 56651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_que_init(&np->comp_ccbq); 56661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 56671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 56681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Initialization for optional handling 56691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * of device queueing. 56701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 56711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING 56721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_que_init(&np->dummy_ccbq); 56731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 56741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 56751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Allocate some CCB. We need at least ONE. 56761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 56771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!sym_alloc_ccb(np)) 56781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto attach_failed; 56791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 56801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 56811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Calculate BUS addresses where we are going 56821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to load the SCRIPTS. 56831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 56841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->scripta_ba = vtobus(np->scripta0); 56851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->scriptb_ba = vtobus(np->scriptb0); 56861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->scriptz_ba = vtobus(np->scriptz0); 56871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 56881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->ram_ba) { 56898637baa3609afff9fe4c65ad4c64d72484c699fcMatthew Wilcox np->scripta_ba = np->ram_ba; 56901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->features & FE_RAM8K) { 56911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->scriptb_ba = np->scripta_ba + 4096; 56921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0 /* May get useful for 64 BIT PCI addressing */ 56931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->scr_ram_seg = cpu_to_scr(np->scripta_ba >> 32); 56941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 56951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 56961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 56971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 56981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 56991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copy scripts to controller instance. 57001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 57011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(np->scripta0, fw->a_base, np->scripta_sz); 57021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(np->scriptb0, fw->b_base, np->scriptb_sz); 57031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(np->scriptz0, fw->z_base, np->scriptz_sz); 57041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 57051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 57061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Setup variable parts in scripts and compute 57071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * scripts bus addresses used from the C code. 57081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 57091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->fw_setup(np, fw); 57101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 57111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 57121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Bind SCRIPTS with physical addresses usable by the 57131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SCRIPTS processor (as seen from the BUS = BUS addresses). 57141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 57151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_fw_bind_script(np, (u32 *) np->scripta0, np->scripta_sz); 57161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_fw_bind_script(np, (u32 *) np->scriptb0, np->scriptb_sz); 57171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_fw_bind_script(np, (u32 *) np->scriptz0, np->scriptz_sz); 57181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 57191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef SYM_CONF_IARB_SUPPORT 57201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 57211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * If user wants IARB to be set when we win arbitration 57221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * and have other jobs, compute the max number of consecutive 57231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * settings of IARB hints before we leave devices a chance to 57241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * arbitrate for reselection. 57251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 57261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef SYM_SETUP_IARB_MAX 57271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->iarb_max = SYM_SETUP_IARB_MAX; 57281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 57291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->iarb_max = 4; 57301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 57311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 57321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 57331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 57341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Prepare the idle and invalid task actions. 57351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 57361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->idletask.start = cpu_to_scr(SCRIPTA_BA(np, idle)); 57371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->idletask.restart = cpu_to_scr(SCRIPTB_BA(np, bad_i_t_l)); 57381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->idletask_ba = vtobus(&np->idletask); 57391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 57401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->notask.start = cpu_to_scr(SCRIPTA_BA(np, idle)); 57411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->notask.restart = cpu_to_scr(SCRIPTB_BA(np, bad_i_t_l)); 57421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->notask_ba = vtobus(&np->notask); 57431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 57441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->bad_itl.start = cpu_to_scr(SCRIPTA_BA(np, idle)); 57451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->bad_itl.restart = cpu_to_scr(SCRIPTB_BA(np, bad_i_t_l)); 57461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->bad_itl_ba = vtobus(&np->bad_itl); 57471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 57481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->bad_itlq.start = cpu_to_scr(SCRIPTA_BA(np, idle)); 57491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->bad_itlq.restart = cpu_to_scr(SCRIPTB_BA(np,bad_i_t_l_q)); 57501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->bad_itlq_ba = vtobus(&np->bad_itlq); 57511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 57521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 57531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Allocate and prepare the lun JUMP table that is used 57541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * for a target prior the probing of devices (bad lun table). 57551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * A private table will be allocated for the target on the 57561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * first INQUIRY response received. 57571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 57581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->badluntbl = sym_calloc_dma(256, "BADLUNTBL"); 57591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!np->badluntbl) 57601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto attach_failed; 57611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 57621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->badlun_sa = cpu_to_scr(SCRIPTB_BA(np, resel_bad_lun)); 57631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0 ; i < 64 ; i++) /* 64 luns/target, no less */ 57641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->badluntbl[i] = cpu_to_scr(vtobus(&np->badlun_sa)); 57651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 57661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 57671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Prepare the bus address array that contains the bus 57681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * address of each target control block. 57691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * For now, assume all logical units are wrong. :) 57701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 57711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (i = 0 ; i < SYM_CONF_MAX_TARGET ; i++) { 57721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->targtbl[i] = cpu_to_scr(vtobus(&np->target[i])); 57731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->target[i].head.luntbl_sa = 57741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cpu_to_scr(vtobus(np->badluntbl)); 57751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds np->target[i].head.lun0_sa = 57761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cpu_to_scr(vtobus(&np->badlun_sa)); 57771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 57781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 57791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 57801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Now check the cache handling of the pci chipset. 57811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 57821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (sym_snooptest (np)) { 57831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printf("%s: CACHE INCORRECTLY CONFIGURED.\n", sym_name(np)); 57841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds goto attach_failed; 57851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 57861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 57871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 57881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Sigh! we are done. 57891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 57901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 57911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 57921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsattach_failed: 57931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENXIO; 57941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 57951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 57961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 57971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Free everything that has been allocated for this device. 57981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 57991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid sym_hcb_free(struct sym_hcb *np) 58001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 58011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds SYM_QUEHEAD *qp; 58021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_ccb *cp; 58031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sym_tcb *tp; 580484e203a279d3de1c8a41a73ab45e55a89bc19345Matthew Wilcox int target; 58051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 58061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->scriptz0) 58071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_mfree_dma(np->scriptz0, np->scriptz_sz, "SCRIPTZ0"); 58081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->scriptb0) 58091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_mfree_dma(np->scriptb0, np->scriptb_sz, "SCRIPTB0"); 58101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->scripta0) 58111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_mfree_dma(np->scripta0, np->scripta_sz, "SCRIPTA0"); 58121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->squeue) 58131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_mfree_dma(np->squeue, sizeof(u32)*(MAX_QUEUE*2), "SQUEUE"); 58141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->dqueue) 58151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_mfree_dma(np->dqueue, sizeof(u32)*(MAX_QUEUE*2), "DQUEUE"); 58161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 58171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->actccbs) { 5818172c122df5186e7cbd413d61757ff90267331002Harvey Harrison while ((qp = sym_remque_head(&np->free_ccbq)) != NULL) { 58191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); 58201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_mfree_dma(cp, sizeof(*cp), "CCB"); 58211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 58221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 58231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(np->ccbh); 58241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 58251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->badluntbl) 58261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_mfree_dma(np->badluntbl, 256,"BADLUNTBL"); 58271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 58281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds for (target = 0; target < SYM_CONF_MAX_TARGET ; target++) { 58291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds tp = &np->target[target]; 5830e41443ec3bb3dc4b12c861e91a5d36feb45f8a46Mike Anderson if (tp->luntbl) 5831e41443ec3bb3dc4b12c861e91a5d36feb45f8a46Mike Anderson sym_mfree_dma(tp->luntbl, 256, "LUNTBL"); 58321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if SYM_CONF_MAX_LUN > 1 58331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds kfree(tp->lunmp); 58341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 58351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 58361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (np->targtbl) 58371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds sym_mfree_dma(np->targtbl, 256, "TARGTBL"); 58381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5839