patch-2.2.6 linux/drivers/scsi/gdth.c
Next file: linux/drivers/scsi/gdth.h
Previous file: linux/drivers/scsi/aha152x.c
Back to the patch index
Back to the overall index
- Lines: 868
- Date:
Mon Apr 12 09:56:16 1999
- Orig file:
v2.2.5/linux/drivers/scsi/gdth.c
- Orig date:
Wed Jan 13 15:00:42 1999
diff -u --recursive --new-file v2.2.5/linux/drivers/scsi/gdth.c linux/drivers/scsi/gdth.c
@@ -2,7 +2,7 @@
* GDT ISA/EISA/PCI Disk Array Controller driver for Linux *
* *
* gdth.c *
- * Copyright (C) 1995-98 ICP vortex Computersysteme GmbH, Achim Leubner *
+ * Copyright (C) 1995-99 ICP vortex Computersysteme GmbH, Achim Leubner *
* *
* <achim@vortex.de> *
* *
@@ -20,9 +20,34 @@
* along with this kernel; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
* *
- * Tested with Linux 1.2.13, ..., 2.1.131 *
+ * Tested with Linux 1.2.13, ..., 2.2.4 *
* *
* $Log: gdth.c,v $
+ * Revision 1.23 1999/03/26 09:12:31 achim
+ * Default value for hdr_channel set to 0
+ *
+ * Revision 1.22 1999/03/22 16:27:16 achim
+ * Bugfix: gdth_store_event() must not be locked with GDTH_LOCK_HA()
+ *
+ * Revision 1.21 1999/03/16 13:40:34 achim
+ * Problems with reserved drives solved
+ * gdth_eh_bus_reset() implemented
+ *
+ * Revision 1.20 1999/03/10 09:08:13 achim
+ * Bugfix: Corrections in gdth_direction_tab[] made
+ * Bugfix: Increase command timeout (gdth_update_timeout()) NOT in gdth_putq()
+ *
+ * Revision 1.19 1999/03/05 14:38:16 achim
+ * Bugfix: Heads/Sectors mapping for reserved devices possibly wrong
+ * -> gdth_eval_mapping() implemented, changes in gdth_bios_param()
+ * INIT_RETRIES set to 100s to avoid DEINIT-Timeout for controllers
+ * with BIOS disabled and memory test set to Intensive
+ * Enhanced /proc support
+ *
+ * Revision 1.18 1999/02/24 09:54:33 achim
+ * Command line parameter hdr_channel implemented
+ * Bugfix for EISA controllers + Linux 2.2.x
+ *
* Revision 1.17 1998/12/17 15:58:11 achim
* Command line parameters implemented
* Changes for Alpha platforms
@@ -95,7 +120,7 @@
* Initial revision
*
************************************************************************/
-#ident "$Id: gdth.c,v 1.17 1998/12/17 15:58:11 achim Exp $"
+#ident "$Id: gdth.c,v 1.23 1999/03/26 09:12:31 achim Exp $"
/* All GDT Disk Array Controllers are fully supported by this driver.
* This includes the PCI/EISA/ISA SCSI Disk Array Controllers and the
@@ -122,9 +147,10 @@
* max_ids:x x - target ID count per channel (1..MAXID)
* rescan:Y rescan all channels/IDs
* rescan:N use all devices found until now
+ * hdr_channel:x x - number of virtual bus for host drives
*
* The default value is: "gdth=disable:N,reserve_mode:1,reverse_scan:N,
- * max_ids:127,rescan:N".
+ * max_ids:127,rescan:N,hdr_channel:0".
* Here is another example: "gdth=reserve_list:0,1,2,0,0,1,3,0,rescan:Y".
*
* When loading the gdth driver as a module, the same options are available.
@@ -134,7 +160,7 @@
* '1' in place of 'Y' and '0' in place of 'N'.
*
* Default: "modprobe gdth disable=0 reserve_mode=1 reverse_scan=0
- * max_ids=127 rescan=0"
+ * max_ids=127 rescan=0 hdr_channel=0"
* The other example: "modprobe gdth reserve_list=0,1,2,0,0,1,3,0 rescan=1".
*/
@@ -179,6 +205,8 @@
#include "gdth.h"
+static void gdth_delay(int milliseconds);
+static void gdth_eval_mapping(ulong32 size, int *cyls, int *heads, int *secs);
#if LINUX_VERSION_CODE >= 0x010346
static void gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs);
#else
@@ -186,7 +214,7 @@
#endif
static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp);
static int gdth_async_event(int hanum,int service);
-static void gdth_log_event(gdth_evt_data *dvr);
+static void gdth_log_event(gdth_evt_data *dvr, char *buffer);
static void gdth_putq(int hanum,Scsi_Cmnd *scp,unchar priority);
static void gdth_next(int hanum);
@@ -226,6 +254,7 @@
static const char *gdth_ctr_name(int hanum);
+#if LINUX_VERSION_CODE >= 0x010300
static void gdth_flush(int hanum);
#if LINUX_VERSION_CODE >= 0x020100
static int gdth_halt(struct notifier_block *nb, ulong event, void *buf);
@@ -233,6 +262,7 @@
static int halt_called = FALSE;
void gdth_halt(void);
#endif
+#endif
#ifdef DEBUG_GDTH
static unchar DebugState = DEBUG_GDTH;
@@ -331,6 +361,7 @@
#define HADATA(a) (&((gdth_ext_str *)((a)->hostdata))->haext)
#define CMDDATA(a) (&((gdth_ext_str *)((a)->hostdata))->cmdext)
+#define BUS_L2P(a,b) ((b)>(a)->virt_bus ? (b-1):(b))
#if LINUX_VERSION_CODE < 0x010300
static void *gdth_mmap(ulong paddr, ulong size)
@@ -429,16 +460,16 @@
static unchar gdth_direction_tab[0x100] = {
DNO,DNO,DIN,DIN,DOU,DIN,DIN,DOU,DIN,DUN,DOU,DOU,DUN,DUN,DUN,DIN,
DNO,DIN,DIN,DOU,DIN,DOU,DNO,DNO,DOU,DNO,DIN,DNO,DIN,DOU,DNO,DUN,
- DIN,DUN,DIN,DUN,DOU,DIN,DUN,DUN,DIN,DIN,DIN,DUN,DUN,DIN,DIN,DIN,
- DIN,DIN,DIN,DNO,DIN,DNO,DNO,DIN,DIN,DIN,DIN,DIN,DIN,DIN,DIN,DIN,
- DIN,DIN,DIN,DIN,DIN,DNO,DUN,DNO,DNO,DNO,DUN,DNO,DIN,DIN,DUN,DUN,
- DUN,DUN,DUN,DUN,DUN,DIN,DUN,DUN,DUN,DUN,DIN,DUN,DUN,DUN,DUN,DUN,
+ DIN,DUN,DIN,DUN,DOU,DIN,DUN,DUN,DIN,DIN,DOU,DNO,DUN,DIN,DOU,DOU,
+ DOU,DOU,DOU,DNO,DIN,DNO,DNO,DIN,DOU,DOU,DOU,DOU,DIN,DOU,DIN,DOU,
+ DOU,DOU,DIN,DIN,DIN,DNO,DUN,DNO,DNO,DNO,DUN,DNO,DOU,DIN,DUN,DUN,
+ DUN,DUN,DUN,DUN,DUN,DOU,DUN,DUN,DUN,DUN,DIN,DUN,DUN,DUN,DUN,DUN,
DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
- DUN,DUN,DUN,DUN,DUN,DNO,DNO,DUN,DIN,DNO,DIN,DUN,DNO,DUN,DIN,DIN,
- DIN,DIN,DIN,DNO,DUN,DIN,DIN,DIN,DIN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
+ DUN,DUN,DUN,DUN,DUN,DNO,DNO,DUN,DIN,DNO,DOU,DUN,DNO,DUN,DOU,DOU,
+ DOU,DOU,DOU,DNO,DUN,DIN,DOU,DIN,DIN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DOU,DUN,DUN,DUN,DUN,DUN,
@@ -474,25 +505,6 @@
#define GDTH_UNLOCK_SCSI_DOCMD() do {} while (0)
#endif
-/* /proc support */
-#if LINUX_VERSION_CODE >= 0x010300
-#include <linux/stat.h>
-struct proc_dir_entry proc_scsi_gdth = {
- PROC_SCSI_GDTH, 4, "gdth",
- S_IFDIR | S_IRUGO | S_IXUGO, 2
-};
-#include "gdth_proc.h"
-#include "gdth_proc.c"
-#endif
-
-#if LINUX_VERSION_CODE >= 0x020100
-/* notifier block to get a notify on system shutdown/halt/reboot */
-static struct notifier_block gdth_notifier = {
- gdth_halt, NULL, 0
-};
-#endif
-
-
/* LILO and modprobe/insmod parameters */
/* IRQ list for GDT3000/3020 EISA controllers */
static int irq[MAXHA] __initdata =
@@ -501,14 +513,16 @@
/* disable driver flag */
static int disable __initdata = 0;
/* reserve flag */
-static int reserve_mode __initdata = 1;
+static int reserve_mode = 1;
/* reserve list */
-static int reserve_list[MAX_RES_ARGS] __initdata =
+static int reserve_list[MAX_RES_ARGS] =
{0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
/* scan order for PCI controllers */
-static int reverse_scan __initdata = 0;
+static int reverse_scan = 0;
+/* virtual channel for the host drives */
+static int hdr_channel = 0;
/* max. IDs per channel */
static int max_ids = MAXID;
/* rescan all IDs */
@@ -522,12 +536,31 @@
MODULE_PARM(reserve_mode, "i");
MODULE_PARM(reserve_list, "4-" __MODULE_STRING(MAX_RES_ARGS) "i");
MODULE_PARM(reverse_scan, "i");
+MODULE_PARM(hdr_channel, "i");
MODULE_PARM(max_ids, "i");
MODULE_PARM(rescan, "i");
MODULE_AUTHOR("Achim Leubner");
#endif
#endif
+/* /proc support */
+#if LINUX_VERSION_CODE >= 0x010300
+#include <linux/stat.h>
+struct proc_dir_entry proc_scsi_gdth = {
+ PROC_SCSI_GDTH, 4, "gdth",
+ S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+#include "gdth_proc.h"
+#include "gdth_proc.c"
+#endif
+
+#if LINUX_VERSION_CODE >= 0x020100
+/* notifier block to get a notify on system shutdown/halt/reboot */
+static struct notifier_block gdth_notifier = {
+ gdth_halt, NULL, 0
+};
+#endif
+
static void gdth_delay(int milliseconds)
{
@@ -544,6 +577,25 @@
}
}
+static void gdth_eval_mapping(ulong32 size, int *cyls, int *heads, int *secs)
+{
+ *cyls = size /HEADS/SECS;
+ if (*cyls <= MAXCYLS) {
+ *heads = HEADS;
+ *secs = SECS;
+ } else { /* too high for 64*32 */
+ *cyls = size /MEDHEADS/MEDSECS;
+ if (*cyls <= MAXCYLS) {
+ *heads = MEDHEADS;
+ *secs = MEDSECS;
+ } else { /* too high for 127*63 */
+ *cyls = size /BIGHEADS/BIGSECS;
+ *heads = BIGHEADS;
+ *secs = BIGSECS;
+ }
+ }
+}
+
/* controller search and initialization functions */
__initfunc (static int gdth_search_eisa(ushort eisa_adr))
@@ -1413,9 +1465,9 @@
ha->pccb->Service |= 0x80;
if (ha->type == GDT_EISA) {
- outb(ha->pccb->Service, ha->bmic + LDOORREG);
if (ha->pccb->OpCode == GDT_INIT) /* store DMA buffer */
- outl((ulong)ha->pccb, ha->bmic + MAILBOXREG);
+ outl(virt_to_bus(ha->pccb), ha->bmic + MAILBOXREG);
+ outb(ha->pccb->Service, ha->bmic + LDOORREG);
} else if (ha->type == GDT_ISA) {
gdth_writeb(0, &((gdt2_dpram_str *)ha->brd)->io.event);
} else if (ha->type == GDT_PCI) {
@@ -1526,11 +1578,15 @@
{
register gdth_ha_str *ha;
ushort cdev_cnt, i;
- ulong32 drv_cyls, drv_hds, drv_secs;
+ int drv_cyls, drv_hds, drv_secs;
ulong32 bus_no;
+ ulong32 drv_cnt, drv_no, j;
gdth_getch_str *chn;
+ gdth_drlist_str *drl;
gdth_iochan_str *ioc;
-
+ gdth_raw_iochan_str *iocr;
+ gdth_arraylist_str *alst;
+
TRACE(("gdth_search_drives() hanum %d\n",hanum));
ha = HADATA(gdth_ctr_tab[hanum]);
@@ -1565,19 +1621,19 @@
cdev_cnt = (ushort)ha->info;
/* detect number of buses - try new IOCTL */
- ioc = (gdth_iochan_str *)ha->pscratch;
- ioc->version = 0xffffffff;
- ioc->list_entries = MAXBUS;
- ioc->first_chan = 0;
- ioc->last_chan = MAXBUS-1;
- ioc->list_offset = GDTOFFSOF(gdth_iochan_str, list[0]);
- if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,GET_IOCHAN_DESC,
- INVALID_CHANNEL,sizeof(gdth_iochan_str))) {
- TRACE2(("GET_IOCHAN_DESC supported!\n"));
- ha->bus_cnt = ioc->chan_count;
+ iocr = (gdth_raw_iochan_str *)ha->pscratch;
+ iocr->hdr.version = 0xffffffff;
+ iocr->hdr.list_entries = MAXBUS;
+ iocr->hdr.first_chan = 0;
+ iocr->hdr.last_chan = MAXBUS-1;
+ iocr->hdr.list_offset = GDTOFFSOF(gdth_raw_iochan_str, list[0]);
+ if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,IOCHAN_RAW_DESC,
+ INVALID_CHANNEL,sizeof(gdth_raw_iochan_str))) {
+ TRACE2(("IOCHAN_RAW_DESC supported!\n"));
+ ha->bus_cnt = iocr->hdr.chan_count;
for (bus_no = 0; bus_no < ha->bus_cnt; ++bus_no) {
- if (ioc->list[bus_no].proc_id < MAXID)
- ha->bus_id[bus_no] = ioc->list[bus_no].proc_id;
+ if (iocr->list[bus_no].proc_id < MAXID)
+ ha->bus_id[bus_no] = iocr->list[bus_no].proc_id;
else
ha->bus_id[bus_no] = 0xff;
}
@@ -1618,16 +1674,100 @@
ha->cpar.version,ha->cpar.state,ha->cpar.strategy,
ha->cpar.write_back,ha->cpar.block_size));
- /* read board info, fill ctr_name[] */
+ /* read board info and features */
+ ha->more_proc = FALSE;
if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,BOARD_INFO,
INVALID_CHANNEL,sizeof(gdth_binfo_str))) {
- TRACE2(("BOARD_INFO supported!\n"));
- strcpy(ha->ctr_name, ((gdth_binfo_str *)ha->pscratch)->type_string);
+ ha->binfo = *(gdth_binfo_str *)ha->pscratch;
+ if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,BOARD_FEATURES,
+ INVALID_CHANNEL,sizeof(gdth_bfeat_str))) {
+ TRACE2(("BOARD_INFO/BOARD_FEATURES supported\n"));
+ ha->bfeat = *(gdth_bfeat_str *)ha->pscratch;
+ ha->more_proc = TRUE;
+ }
} else {
- strcpy(ha->ctr_name, gdth_ctr_name(hanum));
+ TRACE2(("BOARD_INFO requires firmware >= 1.10/2.08\n"));
+ strcpy(ha->binfo.type_string, gdth_ctr_name(hanum));
}
- TRACE2(("Controller name: %s\n",ha->ctr_name));
+ TRACE2(("Controller name: %s\n",ha->binfo.type_string));
+ /* read more informations */
+ if (ha->more_proc) {
+ /* physical drives, channel addresses */
+ ioc = (gdth_iochan_str *)ha->pscratch;
+ ioc->hdr.version = 0xffffffff;
+ ioc->hdr.list_entries = MAXBUS;
+ ioc->hdr.first_chan = 0;
+ ioc->hdr.last_chan = MAXBUS-1;
+ ioc->hdr.list_offset = GDTOFFSOF(gdth_iochan_str, list[0]);
+ if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,IOCHAN_DESC,
+ INVALID_CHANNEL,sizeof(gdth_iochan_str))) {
+ for (bus_no = 0; bus_no < ha->bus_cnt; ++bus_no) {
+ ha->raw[bus_no].address = ioc->list[bus_no].address;
+ ha->raw[bus_no].local_no = ioc->list[bus_no].local_no;
+ }
+ } else {
+ for (bus_no = 0; bus_no < ha->bus_cnt; ++bus_no) {
+ ha->raw[bus_no].address = IO_CHANNEL;
+ ha->raw[bus_no].local_no = bus_no;
+ }
+ }
+ for (bus_no = 0; bus_no < ha->bus_cnt; ++bus_no) {
+ chn = (gdth_getch_str *)ha->pscratch;
+ chn->channel_no = ha->raw[bus_no].local_no;
+ if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,
+ SCSI_CHAN_CNT | L_CTRL_PATTERN,
+ ha->raw[bus_no].address | INVALID_CHANNEL,
+ sizeof(gdth_getch_str))) {
+ ha->raw[bus_no].pdev_cnt = chn->drive_cnt;
+ TRACE2(("Channel %d: %d phys. drives\n",
+ bus_no,chn->drive_cnt));
+ }
+ if (ha->raw[bus_no].pdev_cnt > 0) {
+ drl = (gdth_drlist_str *)ha->pscratch;
+ drl->sc_no = ha->raw[bus_no].local_no;
+ drl->sc_cnt = ha->raw[bus_no].pdev_cnt;
+ if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,
+ SCSI_DR_LIST | L_CTRL_PATTERN,
+ ha->raw[bus_no].address | INVALID_CHANNEL,
+ sizeof(gdth_drlist_str))) {
+ for (j = 0; j < ha->raw[bus_no].pdev_cnt; ++j)
+ ha->raw[bus_no].id_list[j] = drl->sc_list[j];
+ } else {
+ ha->raw[bus_no].pdev_cnt = 0;
+ }
+ }
+ }
+
+ /* logical drives */
+ if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,CACHE_DRV_CNT,
+ INVALID_CHANNEL,sizeof(ulong32))) {
+ drv_cnt = *(ulong32 *)ha->pscratch;
+ if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,CACHE_DRV_LIST,
+ INVALID_CHANNEL,drv_cnt * sizeof(ulong32))) {
+ for (j = 0; j < drv_cnt; ++j) {
+ drv_no = ((ulong32 *)ha->pscratch)[j];
+ if (drv_no < MAX_HDRIVES) {
+ ha->hdr[drv_no].is_logdrv = TRUE;
+ TRACE2(("Drive %d is log. drive\n",drv_no));
+ }
+ }
+ }
+ if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,
+ ARRAY_DRV_LIST | LA_CTRL_PATTERN,
+ 0, 35 * sizeof(gdth_arraylist_str))) {
+ for (j = 0; j < 35; ++j) {
+ alst = &((gdth_arraylist_str *)ha->pscratch)[j];
+ ha->hdr[j].is_arraydrv = alst->is_arrayd;
+ ha->hdr[j].is_master = alst->is_master;
+ ha->hdr[j].is_parity = alst->is_parity;
+ ha->hdr[j].is_hotfix = alst->is_hotfix;
+ ha->hdr[j].master_no = alst->cd_handle;
+ }
+ }
+ }
+ }
+
/* initialize raw service */
if (!gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_INIT,0,0,0)) {
printk("GDT: Initialization error raw service (code %d)\n",
@@ -1695,21 +1835,7 @@
/* evaluate mapping (sectors per head, heads per cylinder) */
ha->hdr[i].size &= ~SECS32;
if (ha->info2 == 0) {
- drv_cyls = ha->hdr[i].size /HEADS/SECS;
- if (drv_cyls <= MAXCYLS) {
- drv_hds = HEADS;
- drv_secs= SECS;
- } else { /* too high for 64*32 */
- drv_cyls = ha->hdr[i].size /MEDHEADS/MEDSECS;
- if (drv_cyls <= MAXCYLS) {
- drv_hds = MEDHEADS;
- drv_secs= MEDSECS;
- } else { /* too high for 127*63 */
- drv_cyls = ha->hdr[i].size /BIGHEADS/BIGSECS;
- drv_hds = BIGHEADS;
- drv_secs= BIGSECS;
- }
- }
+ gdth_eval_mapping(ha->hdr[i].size,&drv_cyls,&drv_hds,&drv_secs);
} else {
drv_hds = ha->info2 & 0xff;
drv_secs = (ha->info2 >> 8) & 0xff;
@@ -1752,7 +1878,6 @@
GDTH_LOCK_HA(ha, flags);
scp->SCp.this_residual = (int)priority;
- gdth_update_timeout(hanum, scp, scp->timeout_per_command * 6);
#if LINUX_VERSION_CODE >= 0x020000
b = scp->channel;
#else
@@ -1761,8 +1886,8 @@
t = scp->target;
#if LINUX_VERSION_CODE >= 0x010300
if (priority >= DEFAULT_PRI) {
- if ((b < ha->bus_cnt && ha->raw[b].lock) ||
- (b == ha->bus_cnt && ha->hdr[t].lock)) {
+ if ((b != ha->virt_bus && ha->raw[BUS_L2P(ha,b)].lock) ||
+ (b == ha->virt_bus && t < MAX_HDRIVES && ha->hdr[t].lock)) {
TRACE2(("gdth_putq(): locked IO -> update_timeout()\n"));
scp->SCp.buffers_residual = gdth_update_timeout(hanum, scp, 0);
}
@@ -1825,8 +1950,8 @@
#endif
t = nscp->target;
if (nscp->SCp.this_residual >= DEFAULT_PRI) {
- if ((b < ha->bus_cnt && ha->raw[b].lock) ||
- (b == ha->bus_cnt && ha->hdr[t].lock))
+ if ((b != ha->virt_bus && ha->raw[BUS_L2P(ha,b)].lock) ||
+ (b == ha->virt_bus && t < MAX_HDRIVES && ha->hdr[t].lock))
continue;
}
@@ -1843,22 +1968,24 @@
firsttime = FALSE;
}
+#if LINUX_VERSION_CODE >= 0x010300
+ if (nscp->done != gdth_scsi_done)
+#endif
+ {
if (nscp->SCp.phase == -1) {
nscp->SCp.phase = SCSIRAWSERVICE; /* default: raw svc. */
if (nscp->cmnd[0] == TEST_UNIT_READY) {
- TRACE2(("TEST_UNIT_READY Bus %d Id %d LUN %d\n",
- nscp->channel, nscp->target, nscp->lun));
+ TRACE2(("TEST_UNIT_READY Bus %d Id %d LUN %d\n",
+ b, t, nscp->lun));
/* TEST_UNIT_READY -> set scan mode */
if ((ha->scan_mode & 0x0f) == 0) {
- if (nscp->channel == 0 && nscp->target == 0 &&
- nscp->lun == 0) {
+ if (b == 0 && t == 0 && nscp->lun == 0) {
ha->scan_mode |= 1;
TRACE2(("Scan mode: 0x%x\n", ha->scan_mode));
}
} else if ((ha->scan_mode & 0x0f) == 1) {
- if (nscp->channel == 0 &&
- ((nscp->target == 0 && nscp->lun == 1) ||
- (nscp->target == 1 && nscp->lun == 0))) {
+ if (b == 0 && ((t == 0 && nscp->lun == 1) ||
+ (t == 1 && nscp->lun == 0))) {
nscp->SCp.Status = GDT_SCAN_START;
nscp->SCp.phase |= ((ha->scan_mode & 0x10 ? 1:0) << 8);
ha->scan_mode = 0x12;
@@ -1869,7 +1996,7 @@
TRACE2(("Scan mode: 0x%x\n", ha->scan_mode));
}
} else if (ha->scan_mode == 0x12) {
- if (b == ha->bus_cnt) {
+ if (b == ha->bus_cnt && t == ha->tid_cnt-1) {
nscp->SCp.Status = GDT_SCAN_END;
ha->scan_mode &= 0x10;
TRACE2(("Scan mode: 0x%x (SCAN_END)\n",
@@ -1878,10 +2005,12 @@
}
}
}
+ }
if (nscp->SCp.Status != -1) {
if ((nscp->SCp.phase & 0xff) == SCSIRAWSERVICE) {
- cmd_index=gdth_fill_raw_cmd(hanum,nscp,b);
+ if (!(cmd_index=gdth_fill_raw_cmd(hanum,nscp,BUS_L2P(ha,b))))
+ this_cmd = FALSE;
next_cmd = FALSE;
}
} else
@@ -1893,13 +2022,15 @@
next_cmd = FALSE;
} else
#endif
- if (b < ha->bus_cnt) {
- if (!(cmd_index=gdth_fill_raw_cmd(hanum,nscp,b))) {
+ if (b != ha->virt_bus) {
+ if (ha->raw[BUS_L2P(ha,b)].io_cnt[t] >= GDTH_MAX_RAW ||
+ !(cmd_index=gdth_fill_raw_cmd(hanum,nscp,BUS_L2P(ha,b))))
this_cmd = FALSE;
- }
- } else if (!ha->hdr[nscp->target].present || nscp->lun != 0) {
+ else
+ ha->raw[BUS_L2P(ha,b)].io_cnt[t]++;
+ } else if (t >= MAX_HDRIVES || !ha->hdr[t].present || nscp->lun != 0) {
TRACE2(("Command 0x%x to bus %d id %d lun %d -> IGNORE\n",
- nscp->cmnd[0], b, nscp->target, nscp->lun));
+ nscp->cmnd[0], b, t, nscp->lun));
nscp->result = DID_BAD_TARGET << 16;
GDTH_UNLOCK_HA(ha,flags);
/* io_request_lock already active ! */
@@ -2405,14 +2536,13 @@
ushort idx, gdth_evt_data *evt)
{
gdth_evt_str *e;
- ulong flags;
struct timeval tv;
+ /* no GDTH_LOCK_HA() ! */
TRACE2(("gdth_store_event() source %d idx %d\n", source, idx));
if (source == 0) /* no source -> no event */
return 0;
- GDTH_LOCK_HA(ha, flags);
if (ebuffer[elastidx].event_source == source &&
ebuffer[elastidx].event_idx == idx &&
!memcmp((char *)&ebuffer[elastidx].event_data.eu,
@@ -2440,7 +2570,6 @@
e->same_count = 1;
e->event_data = *evt;
}
- GDTH_UNLOCK_HA(ha, flags);
return e;
}
@@ -2808,9 +2937,12 @@
printk("\n");
} else {
- scp->SCp.Message = (int)ha->status;
+ if (scp->SCp.Status == -1 && scp->channel != ha->virt_bus) {
+ ha->raw[BUS_L2P(ha,scp->channel)].io_cnt[scp->target]--;
+ }
/* cache or raw service */
if (ha->status == S_OK) {
+ scp->SCp.Message = S_OK;
if (scp->SCp.Status != -1) {
TRACE2(("gdth_sync_event(): special cmd 0x%x OK\n",
scp->SCp.Status));
@@ -2821,8 +2953,10 @@
scp->result = DID_OK << 16;
} else if (ha->status == S_BSY) {
TRACE2(("Controller busy -> retry !\n"));
+ scp->SCp.Message = S_BSY;
return 2;
} else {
+ scp->SCp.Message = (int)((ha->info<<16)|ha->status);
if (scp->SCp.Status != -1) {
TRACE2(("gdth_sync_event(): special cmd 0x%x error 0x%x\n",
scp->SCp.Status, ha->status));
@@ -2836,7 +2970,10 @@
scp->sense_buffer[2] = NOT_READY;
scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
- if (scp->done != gdth_scsi_done) {
+#if LINUX_VERSION_CODE >= 0x010300
+ if (scp->done != gdth_scsi_done)
+#endif
+ {
dvr.size = sizeof(dvr.eu.sync);
dvr.eu.sync.ionode = hanum;
dvr.eu.sync.service = service;
@@ -2904,7 +3041,7 @@
"GDT HA %u, Array Drive %u: parity build failed",
/*18*/ "\005\000\002\006\002"
"GDT HA %u, Array Drive %u: drive rebuild failed",
-/*19*/ "\007\000\002\010\002"
+/*19*/ "\005\000\002\010\002"
"GDT HA %u, Test of Hot Fix %u failed",
/*20*/ "\005\000\002\006\002"
"GDT HA %u, Array Drive %u: drive build finished successfully",
@@ -3066,12 +3203,12 @@
dvr.eu.async.info = ha->info;
*(ulong32 *)dvr.eu.async.scsi_coord = ha->info2;
gdth_store_event(ha, ES_ASYNC, service, &dvr);
- gdth_log_event( &dvr );
+ gdth_log_event( &dvr, NULL );
}
return 1;
}
-static void gdth_log_event(gdth_evt_data *dvr)
+static void gdth_log_event(gdth_evt_data *dvr, char *buffer)
{
gdth_stackframe stack;
char *f = NULL;
@@ -3101,12 +3238,22 @@
break;
}
}
-
- printk(&f[(int)f[0]],stack); printk("\n");
+
+ if (buffer == NULL) {
+ printk(&f[(int)f[0]],stack);
+ printk("\n");
+ } else {
+ sprintf(buffer,&f[(int)f[0]],stack);
+ }
} else {
- printk("GDT: Unknown async. event service %d event no. %d\n",
- dvr->eu.async.service,dvr->eu.async.status);
+ if (buffer == NULL) {
+ printk("GDT HA %u, Unknown async. event service %d event no. %d\n",
+ dvr->eu.async.ionode,dvr->eu.async.service,dvr->eu.async.status);
+ } else {
+ sprintf(buffer,"GDT HA %u, Unknown async. event service %d event no. %d",
+ dvr->eu.async.ionode,dvr->eu.async.service,dvr->eu.async.status);
+ }
}
}
@@ -3249,6 +3396,9 @@
scsi_unregister(shp);
continue;
}
+ if (hdr_channel < 0 || hdr_channel > ha->bus_cnt)
+ hdr_channel = ha->bus_cnt;
+ ha->virt_bus = hdr_channel;
#if LINUX_VERSION_CODE >= 0x020000
shp->max_id = ha->tid_cnt;
@@ -3333,6 +3483,9 @@
scsi_unregister(shp);
continue;
}
+ if (hdr_channel < 0 || hdr_channel > ha->bus_cnt)
+ hdr_channel = ha->bus_cnt;
+ ha->virt_bus = hdr_channel;
#if LINUX_VERSION_CODE >= 0x020000
shp->max_id = ha->tid_cnt;
@@ -3429,6 +3582,9 @@
scsi_unregister(shp);
continue;
}
+ if (hdr_channel < 0 || hdr_channel > ha->bus_cnt)
+ hdr_channel = ha->bus_cnt;
+ ha->virt_bus = hdr_channel;
#if LINUX_VERSION_CODE >= 0x020000
shp->max_id = ha->tid_cnt;
@@ -3479,7 +3635,9 @@
if (NUMDATA(shp)->busnum == 0) {
hanum = NUMDATA(shp)->hanum;
ha = HADATA(gdth_ctr_tab[hanum]);
+#if LINUX_VERSION_CODE >= 0x010300
gdth_flush(hanum);
+#endif
if (shp->irq) {
#if LINUX_VERSION_CODE >= 0x010346
@@ -3552,7 +3710,7 @@
hanum = NUMDATA(shp)->hanum;
ha = HADATA(gdth_ctr_tab[hanum]);
- return ((const char *)ha->ctr_name);
+ return ((const char *)ha->binfo.type_string);
}
/* old error handling */
@@ -3588,8 +3746,33 @@
int gdth_eh_bus_reset(Scsi_Cmnd *scp)
{
+ int i, hanum;
+ gdth_ha_str *ha;
+ ulong flags;
+ Scsi_Cmnd *cmnd;
+
TRACE2(("gdth_eh_bus_reset()\n"));
- return FAILED;
+ hanum = NUMDATA(scp->host)->hanum;
+ ha = HADATA(gdth_ctr_tab[hanum]);
+ if (scp->channel == ha->virt_bus)
+ return FAILED;
+
+ GDTH_LOCK_HA(ha, flags);
+ for (i = 0; i < MAXID; ++i)
+ ha->raw[BUS_L2P(ha,scp->channel)].io_cnt[i] = 0;
+ for (i = 0; i < GDTH_MAXCMDS; ++i) {
+ cmnd = ha->cmd_tab[i].cmnd;
+ if (!SPECIAL_SCP(cmnd) && cmnd->channel == scp->channel)
+ ha->cmd_tab[i].cmnd = UNUSED_CMND;
+ }
+ gdth_polling = TRUE;
+ while (gdth_test_busy(hanum))
+ gdth_delay(0);
+ gdth_internal_cmd(hanum, SCSIRAWSERVICE, GDT_RESET_BUS,
+ BUS_L2P(ha,scp->channel), 0, 0);
+ gdth_polling = FALSE;
+ GDTH_UNLOCK_HA(ha, flags);
+ return SUCCESS;
}
int gdth_eh_host_reset(Scsi_Cmnd *scp)
@@ -3608,7 +3791,6 @@
unchar t;
int hanum;
gdth_ha_str *ha;
- int drv_hds, drv_secs;
hanum = NUMDATA(disk->device->host)->hanum;
t = disk->device->id;
@@ -3616,27 +3798,16 @@
hanum, disk->device->channel, t));
ha = HADATA(gdth_ctr_tab[hanum]);
- if (ha->hdr[t].heads == 0) {
- /* raw device: evaluate mapping (sectors per head, heads per cylinder) */
- if (disk->capacity /HEADS/SECS <= MAXCYLS) {
- drv_hds = HEADS;
- drv_secs= SECS;
- } else if (disk->capacity /MEDHEADS/MEDSECS <= MAXCYLS) {
- drv_hds = MEDHEADS;
- drv_secs= MEDSECS;
- } else {
- drv_hds = BIGHEADS;
- drv_secs= BIGSECS;
- }
- ha->hdr[t].heads = drv_hds;
- ha->hdr[t].secs = drv_secs;
- TRACE2(("gdth_bios_param(): raw device -> params evaluated\n"));
+ if (disk->device->channel != ha->virt_bus || ha->hdr[t].heads == 0) {
+ /* raw device or host drive without mapping information */
+ TRACE2(("Evaluate mapping\n"));
+ gdth_eval_mapping(disk->capacity,&ip[2],&ip[0],&ip[1]);
+ } else {
+ ip[0] = ha->hdr[t].heads;
+ ip[1] = ha->hdr[t].secs;
+ ip[2] = disk->capacity / ip[0] / ip[1];
}
- ip[0] = ha->hdr[t].heads;
- ip[1] = ha->hdr[t].secs;
- ip[2] = disk->capacity / ip[0] / ip[1];
-
TRACE2(("gdth_bios_param(): %d heads, %d secs, %d cyls\n",
ip[0],ip[1],ip[2]));
return 0;
@@ -3683,11 +3854,13 @@
if (scp->done == gdth_scsi_done)
priority = scp->SCp.this_residual;
#endif
+ gdth_update_timeout(hanum, scp, scp->timeout_per_command * 6);
gdth_putq( hanum, scp, priority );
gdth_next( hanum );
return 0;
}
+#if LINUX_VERSION_CODE >= 0x010300
/* flush routine */
static void gdth_flush(int hanum)
{
@@ -3696,7 +3869,6 @@
Scsi_Cmnd scp;
Scsi_Device sdev;
gdth_cmd_str gdtcmd;
- char cmnd[12];
TRACE2(("gdth_flush() hanum %d\n",hanum));
ha = HADATA(gdth_ctr_tab[hanum]);
@@ -3719,18 +3891,7 @@
gdtcmd.u.cache.BlockNo = 1;
gdtcmd.u.cache.sg_canz = 0;
TRACE2(("gdth_flush(): flush ha %d drive %d\n", hanum, i));
- {
- struct semaphore sem = MUTEX_LOCKED;
- scp.request.rq_status = RQ_SCSI_BUSY;
- scp.request.sem = &sem;
- scp.SCp.this_residual = IOCTL_PRI;
- GDTH_LOCK_SCSI_DOCMD();
- scsi_do_cmd(&scp, cmnd, &gdtcmd,
- sizeof(gdth_cmd_str), gdth_scsi_done,
- 30*HZ, 1);
- GDTH_UNLOCK_SCSI_DOCMD();
- down(&sem);
- }
+ gdth_do_cmd(&scp, &gdtcmd, 30);
}
}
}
@@ -3747,7 +3908,6 @@
Scsi_Cmnd scp;
Scsi_Device sdev;
gdth_cmd_str gdtcmd;
- char cmnd[12];
#endif
#if LINUX_VERSION_CODE >= 0x020100
@@ -3782,18 +3942,7 @@
gdtcmd.Service = CACHESERVICE;
gdtcmd.OpCode = GDT_RESET;
TRACE2(("gdth_halt(): reset controller %d\n", hanum));
- {
- struct semaphore sem = MUTEX_LOCKED;
- scp.request.rq_status = RQ_SCSI_BUSY;
- scp.request.sem = &sem;
- scp.SCp.this_residual = IOCTL_PRI;
- GDTH_LOCK_SCSI_DOCMD();
- scsi_do_cmd(&scp, cmnd, &gdtcmd,
- sizeof(gdth_cmd_str), gdth_scsi_done,
- 10*HZ, 1);
- GDTH_UNLOCK_SCSI_DOCMD();
- down(&sem);
- }
+ gdth_do_cmd(&scp, &gdtcmd, 10);
#endif
}
printk("Done.\n");
@@ -3806,6 +3955,7 @@
return NOTIFY_OK;
#endif
}
+#endif
/* called from init/main.c */
@@ -3846,6 +3996,8 @@
reserve_mode = val;
else if (!strncmp(argv, "reverse_scan:", 13))
reverse_scan = val;
+ else if (!strncmp(argv, "hdr_channel:", 12))
+ hdr_channel = val;
else if (!strncmp(argv, "max_ids:", 8))
max_ids = val;
else if (!strncmp(argv, "rescan:", 7))
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)