diff options
Diffstat (limited to 'drivers/scsi')
33 files changed, 17105 insertions, 1 deletions
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index d61662c1a0ee..7de5fdfdab67 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig | |||
@@ -209,7 +209,7 @@ config SCSI_LOGGING | |||
209 | there should be no noticeable performance impact as long as you have | 209 | there should be no noticeable performance impact as long as you have |
210 | logging turned off. | 210 | logging turned off. |
211 | 211 | ||
212 | menu "SCSI Transport Attributes" | 212 | menu "SCSI Transports" |
213 | depends on SCSI | 213 | depends on SCSI |
214 | 214 | ||
215 | config SCSI_SPI_ATTRS | 215 | config SCSI_SPI_ATTRS |
@@ -242,6 +242,8 @@ config SCSI_SAS_ATTRS | |||
242 | If you wish to export transport-specific information about | 242 | If you wish to export transport-specific information about |
243 | each attached SAS device to sysfs, say Y. | 243 | each attached SAS device to sysfs, say Y. |
244 | 244 | ||
245 | source "drivers/scsi/libsas/Kconfig" | ||
246 | |||
245 | endmenu | 247 | endmenu |
246 | 248 | ||
247 | menu "SCSI low-level drivers" | 249 | menu "SCSI low-level drivers" |
@@ -431,6 +433,7 @@ config SCSI_AIC7XXX_OLD | |||
431 | module will be called aic7xxx_old. | 433 | module will be called aic7xxx_old. |
432 | 434 | ||
433 | source "drivers/scsi/aic7xxx/Kconfig.aic79xx" | 435 | source "drivers/scsi/aic7xxx/Kconfig.aic79xx" |
436 | source "drivers/scsi/aic94xx/Kconfig" | ||
434 | 437 | ||
435 | # All the I2O code and drivers do not seem to be 64bit safe. | 438 | # All the I2O code and drivers do not seem to be 64bit safe. |
436 | config SCSI_DPT_I2O | 439 | config SCSI_DPT_I2O |
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index b2de9bfdfdcd..83da70decdd1 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile | |||
@@ -32,6 +32,7 @@ obj-$(CONFIG_SCSI_SPI_ATTRS) += scsi_transport_spi.o | |||
32 | obj-$(CONFIG_SCSI_FC_ATTRS) += scsi_transport_fc.o | 32 | obj-$(CONFIG_SCSI_FC_ATTRS) += scsi_transport_fc.o |
33 | obj-$(CONFIG_SCSI_ISCSI_ATTRS) += scsi_transport_iscsi.o | 33 | obj-$(CONFIG_SCSI_ISCSI_ATTRS) += scsi_transport_iscsi.o |
34 | obj-$(CONFIG_SCSI_SAS_ATTRS) += scsi_transport_sas.o | 34 | obj-$(CONFIG_SCSI_SAS_ATTRS) += scsi_transport_sas.o |
35 | obj-$(CONFIG_SCSI_SAS_LIBSAS) += libsas/ | ||
35 | 36 | ||
36 | obj-$(CONFIG_ISCSI_TCP) += libiscsi.o iscsi_tcp.o | 37 | obj-$(CONFIG_ISCSI_TCP) += libiscsi.o iscsi_tcp.o |
37 | obj-$(CONFIG_INFINIBAND_ISER) += libiscsi.o | 38 | obj-$(CONFIG_INFINIBAND_ISER) += libiscsi.o |
@@ -68,6 +69,7 @@ obj-$(CONFIG_SCSI_AIC7XXX) += aic7xxx/ | |||
68 | obj-$(CONFIG_SCSI_AIC79XX) += aic7xxx/ | 69 | obj-$(CONFIG_SCSI_AIC79XX) += aic7xxx/ |
69 | obj-$(CONFIG_SCSI_AACRAID) += aacraid/ | 70 | obj-$(CONFIG_SCSI_AACRAID) += aacraid/ |
70 | obj-$(CONFIG_SCSI_AIC7XXX_OLD) += aic7xxx_old.o | 71 | obj-$(CONFIG_SCSI_AIC7XXX_OLD) += aic7xxx_old.o |
72 | obj-$(CONFIG_SCSI_AIC94XX) += aic94xx/ | ||
71 | obj-$(CONFIG_SCSI_IPS) += ips.o | 73 | obj-$(CONFIG_SCSI_IPS) += ips.o |
72 | obj-$(CONFIG_SCSI_FD_MCS) += fd_mcs.o | 74 | obj-$(CONFIG_SCSI_FD_MCS) += fd_mcs.o |
73 | obj-$(CONFIG_SCSI_FUTURE_DOMAIN)+= fdomain.o | 75 | obj-$(CONFIG_SCSI_FUTURE_DOMAIN)+= fdomain.o |
diff --git a/drivers/scsi/aic94xx/Kconfig b/drivers/scsi/aic94xx/Kconfig new file mode 100644 index 000000000000..0ed391d8ee84 --- /dev/null +++ b/drivers/scsi/aic94xx/Kconfig | |||
@@ -0,0 +1,41 @@ | |||
1 | # | ||
2 | # Kernel configuration file for aic94xx SAS/SATA driver. | ||
3 | # | ||
4 | # Copyright (c) 2005 Adaptec, Inc. All rights reserved. | ||
5 | # Copyright (c) 2005 Luben Tuikov <luben_tuikov@adaptec.com> | ||
6 | # | ||
7 | # This file is licensed under GPLv2. | ||
8 | # | ||
9 | # This file is part of the aic94xx driver. | ||
10 | # | ||
11 | # The aic94xx driver is free software; you can redistribute it and/or | ||
12 | # modify it under the terms of the GNU General Public License as | ||
13 | # published by the Free Software Foundation; version 2 of the | ||
14 | # License. | ||
15 | # | ||
16 | # The aic94xx driver is distributed in the hope that it will be useful, | ||
17 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
19 | # General Public License for more details. | ||
20 | # | ||
21 | # You should have received a copy of the GNU General Public License | ||
22 | # along with Aic94xx Driver; if not, write to the Free Software | ||
23 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
24 | # | ||
25 | # | ||
26 | |||
27 | config SCSI_AIC94XX | ||
28 | tristate "Adaptec AIC94xx SAS/SATA support" | ||
29 | depends on PCI | ||
30 | select SCSI_SAS_LIBSAS | ||
31 | help | ||
32 | This driver supports Adaptec's SAS/SATA 3Gb/s 64 bit PCI-X | ||
33 | AIC94xx chip based host adapters. | ||
34 | |||
35 | config AIC94XX_DEBUG | ||
36 | bool "Compile in debug mode" | ||
37 | default y | ||
38 | depends on SCSI_AIC94XX | ||
39 | help | ||
40 | Compiles the aic94xx driver in debug mode. In debug mode, | ||
41 | the driver prints some messages to the console. | ||
diff --git a/drivers/scsi/aic94xx/Makefile b/drivers/scsi/aic94xx/Makefile new file mode 100644 index 000000000000..e6b70123940c --- /dev/null +++ b/drivers/scsi/aic94xx/Makefile | |||
@@ -0,0 +1,39 @@ | |||
1 | # | ||
2 | # Makefile for Adaptec aic94xx SAS/SATA driver. | ||
3 | # | ||
4 | # Copyright (C) 2005 Adaptec, Inc. All rights reserved. | ||
5 | # Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> | ||
6 | # | ||
7 | # This file is licensed under GPLv2. | ||
8 | # | ||
9 | # This file is part of the the aic94xx driver. | ||
10 | # | ||
11 | # The aic94xx driver is free software; you can redistribute it and/or | ||
12 | # modify it under the terms of the GNU General Public License as | ||
13 | # published by the Free Software Foundation; version 2 of the | ||
14 | # License. | ||
15 | # | ||
16 | # The aic94xx driver is distributed in the hope that it will be useful, | ||
17 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
19 | # General Public License for more details. | ||
20 | # | ||
21 | # You should have received a copy of the GNU General Public License | ||
22 | # along with the aic94xx driver; if not, write to the Free Software | ||
23 | # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
24 | |||
25 | ifeq ($(CONFIG_AIC94XX_DEBUG),y) | ||
26 | EXTRA_CFLAGS += -DASD_DEBUG -DASD_ENTER_EXIT | ||
27 | endif | ||
28 | |||
29 | obj-$(CONFIG_SCSI_AIC94XX) += aic94xx.o | ||
30 | aic94xx-y += aic94xx_init.o \ | ||
31 | aic94xx_hwi.o \ | ||
32 | aic94xx_reg.o \ | ||
33 | aic94xx_sds.o \ | ||
34 | aic94xx_seq.o \ | ||
35 | aic94xx_dump.o \ | ||
36 | aic94xx_scb.o \ | ||
37 | aic94xx_dev.o \ | ||
38 | aic94xx_tmf.o \ | ||
39 | aic94xx_task.o | ||
diff --git a/drivers/scsi/aic94xx/aic94xx.h b/drivers/scsi/aic94xx/aic94xx.h new file mode 100644 index 000000000000..cb7caf1c9ce1 --- /dev/null +++ b/drivers/scsi/aic94xx/aic94xx.h | |||
@@ -0,0 +1,114 @@ | |||
1 | /* | ||
2 | * Aic94xx SAS/SATA driver header file. | ||
3 | * | ||
4 | * Copyright (C) 2005 Adaptec, Inc. All rights reserved. | ||
5 | * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> | ||
6 | * | ||
7 | * This file is licensed under GPLv2. | ||
8 | * | ||
9 | * This file is part of the aic94xx driver. | ||
10 | * | ||
11 | * The aic94xx driver is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License as | ||
13 | * published by the Free Software Foundation; version 2 of the | ||
14 | * License. | ||
15 | * | ||
16 | * The aic94xx driver is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
19 | * General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with the aic94xx driver; if not, write to the Free Software | ||
23 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
24 | * | ||
25 | * $Id: //depot/aic94xx/aic94xx.h#31 $ | ||
26 | */ | ||
27 | |||
28 | #ifndef _AIC94XX_H_ | ||
29 | #define _AIC94XX_H_ | ||
30 | |||
31 | #include <linux/slab.h> | ||
32 | #include <linux/ctype.h> | ||
33 | #include <scsi/libsas.h> | ||
34 | |||
35 | #define ASD_DRIVER_NAME "aic94xx" | ||
36 | #define ASD_DRIVER_DESCRIPTION "Adaptec aic94xx SAS/SATA driver" | ||
37 | |||
38 | #define asd_printk(fmt, ...) printk(KERN_NOTICE ASD_DRIVER_NAME ": " fmt, ## __VA_ARGS__) | ||
39 | |||
40 | #ifdef ASD_ENTER_EXIT | ||
41 | #define ENTER printk(KERN_NOTICE "%s: ENTER %s\n", ASD_DRIVER_NAME, \ | ||
42 | __FUNCTION__) | ||
43 | #define EXIT printk(KERN_NOTICE "%s: --EXIT %s\n", ASD_DRIVER_NAME, \ | ||
44 | __FUNCTION__) | ||
45 | #else | ||
46 | #define ENTER | ||
47 | #define EXIT | ||
48 | #endif | ||
49 | |||
50 | #ifdef ASD_DEBUG | ||
51 | #define ASD_DPRINTK asd_printk | ||
52 | #else | ||
53 | #define ASD_DPRINTK(fmt, ...) | ||
54 | #endif | ||
55 | |||
56 | /* 2*ITNL timeout + 1 second */ | ||
57 | #define AIC94XX_SCB_TIMEOUT (5*HZ) | ||
58 | |||
59 | extern kmem_cache_t *asd_dma_token_cache; | ||
60 | extern kmem_cache_t *asd_ascb_cache; | ||
61 | extern char sas_addr_str[2*SAS_ADDR_SIZE + 1]; | ||
62 | |||
63 | static inline void asd_stringify_sas_addr(char *p, const u8 *sas_addr) | ||
64 | { | ||
65 | int i; | ||
66 | for (i = 0; i < SAS_ADDR_SIZE; i++, p += 2) | ||
67 | snprintf(p, 3, "%02X", sas_addr[i]); | ||
68 | *p = '\0'; | ||
69 | } | ||
70 | |||
71 | static inline void asd_destringify_sas_addr(u8 *sas_addr, const char *p) | ||
72 | { | ||
73 | int i; | ||
74 | for (i = 0; i < SAS_ADDR_SIZE; i++) { | ||
75 | u8 h, l; | ||
76 | if (!*p) | ||
77 | break; | ||
78 | h = isdigit(*p) ? *p-'0' : *p-'A'+10; | ||
79 | p++; | ||
80 | l = isdigit(*p) ? *p-'0' : *p-'A'+10; | ||
81 | p++; | ||
82 | sas_addr[i] = (h<<4) | l; | ||
83 | } | ||
84 | } | ||
85 | |||
86 | struct asd_ha_struct; | ||
87 | struct asd_ascb; | ||
88 | |||
89 | int asd_read_ocm(struct asd_ha_struct *asd_ha); | ||
90 | int asd_read_flash(struct asd_ha_struct *asd_ha); | ||
91 | |||
92 | int asd_dev_found(struct domain_device *dev); | ||
93 | void asd_dev_gone(struct domain_device *dev); | ||
94 | |||
95 | void asd_invalidate_edb(struct asd_ascb *ascb, int edb_id); | ||
96 | |||
97 | int asd_execute_task(struct sas_task *, int num, unsigned long gfp_flags); | ||
98 | |||
99 | /* ---------- TMFs ---------- */ | ||
100 | int asd_abort_task(struct sas_task *); | ||
101 | int asd_abort_task_set(struct domain_device *, u8 *lun); | ||
102 | int asd_clear_aca(struct domain_device *, u8 *lun); | ||
103 | int asd_clear_task_set(struct domain_device *, u8 *lun); | ||
104 | int asd_lu_reset(struct domain_device *, u8 *lun); | ||
105 | int asd_query_task(struct sas_task *); | ||
106 | |||
107 | /* ---------- Adapter and Port management ---------- */ | ||
108 | int asd_clear_nexus_port(struct asd_sas_port *port); | ||
109 | int asd_clear_nexus_ha(struct sas_ha_struct *sas_ha); | ||
110 | |||
111 | /* ---------- Phy Management ---------- */ | ||
112 | int asd_control_phy(struct asd_sas_phy *phy, enum phy_func func); | ||
113 | |||
114 | #endif | ||
diff --git a/drivers/scsi/aic94xx/aic94xx_dev.c b/drivers/scsi/aic94xx/aic94xx_dev.c new file mode 100644 index 000000000000..6f8901b748f7 --- /dev/null +++ b/drivers/scsi/aic94xx/aic94xx_dev.c | |||
@@ -0,0 +1,353 @@ | |||
1 | /* | ||
2 | * Aic94xx SAS/SATA DDB management | ||
3 | * | ||
4 | * Copyright (C) 2005 Adaptec, Inc. All rights reserved. | ||
5 | * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> | ||
6 | * | ||
7 | * This file is licensed under GPLv2. | ||
8 | * | ||
9 | * This file is part of the aic94xx driver. | ||
10 | * | ||
11 | * The aic94xx driver is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License as | ||
13 | * published by the Free Software Foundation; version 2 of the | ||
14 | * License. | ||
15 | * | ||
16 | * The aic94xx driver is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
19 | * General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with the aic94xx driver; if not, write to the Free Software | ||
23 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
24 | * | ||
25 | * $Id: //depot/aic94xx/aic94xx_dev.c#21 $ | ||
26 | */ | ||
27 | |||
28 | #include "aic94xx.h" | ||
29 | #include "aic94xx_hwi.h" | ||
30 | #include "aic94xx_reg.h" | ||
31 | #include "aic94xx_sas.h" | ||
32 | |||
33 | #define FIND_FREE_DDB(_ha) find_first_zero_bit((_ha)->hw_prof.ddb_bitmap, \ | ||
34 | (_ha)->hw_prof.max_ddbs) | ||
35 | #define SET_DDB(_ddb, _ha) set_bit(_ddb, (_ha)->hw_prof.ddb_bitmap) | ||
36 | #define CLEAR_DDB(_ddb, _ha) clear_bit(_ddb, (_ha)->hw_prof.ddb_bitmap) | ||
37 | |||
38 | static inline int asd_get_ddb(struct asd_ha_struct *asd_ha) | ||
39 | { | ||
40 | unsigned long flags; | ||
41 | int ddb, i; | ||
42 | |||
43 | spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags); | ||
44 | ddb = FIND_FREE_DDB(asd_ha); | ||
45 | if (ddb >= asd_ha->hw_prof.max_ddbs) { | ||
46 | ddb = -ENOMEM; | ||
47 | spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags); | ||
48 | goto out; | ||
49 | } | ||
50 | SET_DDB(ddb, asd_ha); | ||
51 | spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags); | ||
52 | |||
53 | for (i = 0; i < sizeof(struct asd_ddb_ssp_smp_target_port); i+= 4) | ||
54 | asd_ddbsite_write_dword(asd_ha, ddb, i, 0); | ||
55 | out: | ||
56 | return ddb; | ||
57 | } | ||
58 | |||
59 | #define INIT_CONN_TAG offsetof(struct asd_ddb_ssp_smp_target_port, init_conn_tag) | ||
60 | #define DEST_SAS_ADDR offsetof(struct asd_ddb_ssp_smp_target_port, dest_sas_addr) | ||
61 | #define SEND_QUEUE_HEAD offsetof(struct asd_ddb_ssp_smp_target_port, send_queue_head) | ||
62 | #define DDB_TYPE offsetof(struct asd_ddb_ssp_smp_target_port, ddb_type) | ||
63 | #define CONN_MASK offsetof(struct asd_ddb_ssp_smp_target_port, conn_mask) | ||
64 | #define DDB_TARG_FLAGS offsetof(struct asd_ddb_ssp_smp_target_port, flags) | ||
65 | #define DDB_TARG_FLAGS2 offsetof(struct asd_ddb_stp_sata_target_port, flags2) | ||
66 | #define EXEC_QUEUE_TAIL offsetof(struct asd_ddb_ssp_smp_target_port, exec_queue_tail) | ||
67 | #define SEND_QUEUE_TAIL offsetof(struct asd_ddb_ssp_smp_target_port, send_queue_tail) | ||
68 | #define SISTER_DDB offsetof(struct asd_ddb_ssp_smp_target_port, sister_ddb) | ||
69 | #define MAX_CCONN offsetof(struct asd_ddb_ssp_smp_target_port, max_concurrent_conn) | ||
70 | #define NUM_CTX offsetof(struct asd_ddb_ssp_smp_target_port, num_contexts) | ||
71 | #define ATA_CMD_SCBPTR offsetof(struct asd_ddb_stp_sata_target_port, ata_cmd_scbptr) | ||
72 | #define SATA_TAG_ALLOC_MASK offsetof(struct asd_ddb_stp_sata_target_port, sata_tag_alloc_mask) | ||
73 | #define NUM_SATA_TAGS offsetof(struct asd_ddb_stp_sata_target_port, num_sata_tags) | ||
74 | #define SATA_STATUS offsetof(struct asd_ddb_stp_sata_target_port, sata_status) | ||
75 | #define NCQ_DATA_SCB_PTR offsetof(struct asd_ddb_stp_sata_target_port, ncq_data_scb_ptr) | ||
76 | #define ITNL_TIMEOUT offsetof(struct asd_ddb_ssp_smp_target_port, itnl_timeout) | ||
77 | |||
78 | static inline void asd_free_ddb(struct asd_ha_struct *asd_ha, int ddb) | ||
79 | { | ||
80 | unsigned long flags; | ||
81 | |||
82 | if (!ddb || ddb >= 0xFFFF) | ||
83 | return; | ||
84 | asd_ddbsite_write_byte(asd_ha, ddb, DDB_TYPE, DDB_TYPE_UNUSED); | ||
85 | spin_lock_irqsave(&asd_ha->hw_prof.ddb_lock, flags); | ||
86 | CLEAR_DDB(ddb, asd_ha); | ||
87 | spin_unlock_irqrestore(&asd_ha->hw_prof.ddb_lock, flags); | ||
88 | } | ||
89 | |||
90 | static inline void asd_set_ddb_type(struct domain_device *dev) | ||
91 | { | ||
92 | struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha; | ||
93 | int ddb = (int) (unsigned long) dev->lldd_dev; | ||
94 | |||
95 | if (dev->dev_type == SATA_PM_PORT) | ||
96 | asd_ddbsite_write_byte(asd_ha,ddb, DDB_TYPE, DDB_TYPE_PM_PORT); | ||
97 | else if (dev->tproto) | ||
98 | asd_ddbsite_write_byte(asd_ha,ddb, DDB_TYPE, DDB_TYPE_TARGET); | ||
99 | else | ||
100 | asd_ddbsite_write_byte(asd_ha,ddb,DDB_TYPE,DDB_TYPE_INITIATOR); | ||
101 | } | ||
102 | |||
103 | static int asd_init_sata_tag_ddb(struct domain_device *dev) | ||
104 | { | ||
105 | struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha; | ||
106 | int ddb, i; | ||
107 | |||
108 | ddb = asd_get_ddb(asd_ha); | ||
109 | if (ddb < 0) | ||
110 | return ddb; | ||
111 | |||
112 | for (i = 0; i < sizeof(struct asd_ddb_sata_tag); i += 2) | ||
113 | asd_ddbsite_write_word(asd_ha, ddb, i, 0xFFFF); | ||
114 | |||
115 | asd_ddbsite_write_word(asd_ha, (int) (unsigned long) dev->lldd_dev, | ||
116 | SISTER_DDB, ddb); | ||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | static inline int asd_init_sata(struct domain_device *dev) | ||
121 | { | ||
122 | struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha; | ||
123 | int ddb = (int) (unsigned long) dev->lldd_dev; | ||
124 | u32 qdepth = 0; | ||
125 | int res = 0; | ||
126 | |||
127 | asd_ddbsite_write_word(asd_ha, ddb, ATA_CMD_SCBPTR, 0xFFFF); | ||
128 | if ((dev->dev_type == SATA_DEV || dev->dev_type == SATA_PM_PORT) && | ||
129 | dev->sata_dev.identify_device && | ||
130 | dev->sata_dev.identify_device[10] != 0) { | ||
131 | u16 w75 = le16_to_cpu(dev->sata_dev.identify_device[75]); | ||
132 | u16 w76 = le16_to_cpu(dev->sata_dev.identify_device[76]); | ||
133 | |||
134 | if (w76 & 0x100) /* NCQ? */ | ||
135 | qdepth = (w75 & 0x1F) + 1; | ||
136 | asd_ddbsite_write_dword(asd_ha, ddb, SATA_TAG_ALLOC_MASK, | ||
137 | (1<<qdepth)-1); | ||
138 | asd_ddbsite_write_byte(asd_ha, ddb, NUM_SATA_TAGS, qdepth); | ||
139 | } | ||
140 | if (dev->dev_type == SATA_DEV || dev->dev_type == SATA_PM || | ||
141 | dev->dev_type == SATA_PM_PORT) { | ||
142 | struct dev_to_host_fis *fis = (struct dev_to_host_fis *) | ||
143 | dev->frame_rcvd; | ||
144 | asd_ddbsite_write_byte(asd_ha, ddb, SATA_STATUS, fis->status); | ||
145 | } | ||
146 | asd_ddbsite_write_word(asd_ha, ddb, NCQ_DATA_SCB_PTR, 0xFFFF); | ||
147 | if (qdepth > 0) | ||
148 | res = asd_init_sata_tag_ddb(dev); | ||
149 | return res; | ||
150 | } | ||
151 | |||
152 | static int asd_init_target_ddb(struct domain_device *dev) | ||
153 | { | ||
154 | int ddb, i; | ||
155 | struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha; | ||
156 | u8 flags = 0; | ||
157 | |||
158 | ddb = asd_get_ddb(asd_ha); | ||
159 | if (ddb < 0) | ||
160 | return ddb; | ||
161 | |||
162 | dev->lldd_dev = (void *) (unsigned long) ddb; | ||
163 | |||
164 | asd_ddbsite_write_byte(asd_ha, ddb, 0, DDB_TP_CONN_TYPE); | ||
165 | asd_ddbsite_write_byte(asd_ha, ddb, 1, 0); | ||
166 | asd_ddbsite_write_word(asd_ha, ddb, INIT_CONN_TAG, 0xFFFF); | ||
167 | for (i = 0; i < SAS_ADDR_SIZE; i++) | ||
168 | asd_ddbsite_write_byte(asd_ha, ddb, DEST_SAS_ADDR+i, | ||
169 | dev->sas_addr[i]); | ||
170 | asd_ddbsite_write_word(asd_ha, ddb, SEND_QUEUE_HEAD, 0xFFFF); | ||
171 | asd_set_ddb_type(dev); | ||
172 | asd_ddbsite_write_byte(asd_ha, ddb, CONN_MASK, dev->port->phy_mask); | ||
173 | if (dev->port->oob_mode != SATA_OOB_MODE) { | ||
174 | flags |= OPEN_REQUIRED; | ||
175 | if ((dev->dev_type == SATA_DEV) || | ||
176 | (dev->tproto & SAS_PROTO_STP)) { | ||
177 | struct smp_resp *rps_resp = &dev->sata_dev.rps_resp; | ||
178 | if (rps_resp->frame_type == SMP_RESPONSE && | ||
179 | rps_resp->function == SMP_REPORT_PHY_SATA && | ||
180 | rps_resp->result == SMP_RESP_FUNC_ACC) { | ||
181 | if (rps_resp->rps.affil_valid) | ||
182 | flags |= STP_AFFIL_POL; | ||
183 | if (rps_resp->rps.affil_supp) | ||
184 | flags |= SUPPORTS_AFFIL; | ||
185 | } | ||
186 | } else { | ||
187 | flags |= CONCURRENT_CONN_SUPP; | ||
188 | if (!dev->parent && | ||
189 | (dev->dev_type == EDGE_DEV || | ||
190 | dev->dev_type == FANOUT_DEV)) | ||
191 | asd_ddbsite_write_byte(asd_ha, ddb, MAX_CCONN, | ||
192 | 4); | ||
193 | else | ||
194 | asd_ddbsite_write_byte(asd_ha, ddb, MAX_CCONN, | ||
195 | dev->pathways); | ||
196 | asd_ddbsite_write_byte(asd_ha, ddb, NUM_CTX, 1); | ||
197 | } | ||
198 | } | ||
199 | if (dev->dev_type == SATA_PM) | ||
200 | flags |= SATA_MULTIPORT; | ||
201 | asd_ddbsite_write_byte(asd_ha, ddb, DDB_TARG_FLAGS, flags); | ||
202 | |||
203 | flags = 0; | ||
204 | if (dev->tproto & SAS_PROTO_STP) | ||
205 | flags |= STP_CL_POL_NO_TX; | ||
206 | asd_ddbsite_write_byte(asd_ha, ddb, DDB_TARG_FLAGS2, flags); | ||
207 | |||
208 | asd_ddbsite_write_word(asd_ha, ddb, EXEC_QUEUE_TAIL, 0xFFFF); | ||
209 | asd_ddbsite_write_word(asd_ha, ddb, SEND_QUEUE_TAIL, 0xFFFF); | ||
210 | asd_ddbsite_write_word(asd_ha, ddb, SISTER_DDB, 0xFFFF); | ||
211 | |||
212 | if (dev->dev_type == SATA_DEV || (dev->tproto & SAS_PROTO_STP)) { | ||
213 | i = asd_init_sata(dev); | ||
214 | if (i < 0) { | ||
215 | asd_free_ddb(asd_ha, ddb); | ||
216 | return i; | ||
217 | } | ||
218 | } | ||
219 | |||
220 | if (dev->dev_type == SAS_END_DEV) { | ||
221 | struct sas_end_device *rdev = rphy_to_end_device(dev->rphy); | ||
222 | if (rdev->I_T_nexus_loss_timeout > 0) | ||
223 | asd_ddbsite_write_word(asd_ha, ddb, ITNL_TIMEOUT, | ||
224 | min(rdev->I_T_nexus_loss_timeout, | ||
225 | (u16)ITNL_TIMEOUT_CONST)); | ||
226 | else | ||
227 | asd_ddbsite_write_word(asd_ha, ddb, ITNL_TIMEOUT, | ||
228 | (u16)ITNL_TIMEOUT_CONST); | ||
229 | } | ||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | static int asd_init_sata_pm_table_ddb(struct domain_device *dev) | ||
234 | { | ||
235 | struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha; | ||
236 | int ddb, i; | ||
237 | |||
238 | ddb = asd_get_ddb(asd_ha); | ||
239 | if (ddb < 0) | ||
240 | return ddb; | ||
241 | |||
242 | for (i = 0; i < 32; i += 2) | ||
243 | asd_ddbsite_write_word(asd_ha, ddb, i, 0xFFFF); | ||
244 | |||
245 | asd_ddbsite_write_word(asd_ha, (int) (unsigned long) dev->lldd_dev, | ||
246 | SISTER_DDB, ddb); | ||
247 | |||
248 | return 0; | ||
249 | } | ||
250 | |||
251 | #define PM_PORT_FLAGS offsetof(struct asd_ddb_sata_pm_port, pm_port_flags) | ||
252 | #define PARENT_DDB offsetof(struct asd_ddb_sata_pm_port, parent_ddb) | ||
253 | |||
254 | /** | ||
255 | * asd_init_sata_pm_port_ddb -- SATA Port Multiplier Port | ||
256 | * dev: pointer to domain device | ||
257 | * | ||
258 | * For SATA Port Multiplier Ports we need to allocate one SATA Port | ||
259 | * Multiplier Port DDB and depending on whether the target on it | ||
260 | * supports SATA II NCQ, one SATA Tag DDB. | ||
261 | */ | ||
262 | static int asd_init_sata_pm_port_ddb(struct domain_device *dev) | ||
263 | { | ||
264 | int ddb, i, parent_ddb, pmtable_ddb; | ||
265 | struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha; | ||
266 | u8 flags; | ||
267 | |||
268 | ddb = asd_get_ddb(asd_ha); | ||
269 | if (ddb < 0) | ||
270 | return ddb; | ||
271 | |||
272 | asd_set_ddb_type(dev); | ||
273 | flags = (dev->sata_dev.port_no << 4) | PM_PORT_SET; | ||
274 | asd_ddbsite_write_byte(asd_ha, ddb, PM_PORT_FLAGS, flags); | ||
275 | asd_ddbsite_write_word(asd_ha, ddb, SISTER_DDB, 0xFFFF); | ||
276 | asd_ddbsite_write_word(asd_ha, ddb, ATA_CMD_SCBPTR, 0xFFFF); | ||
277 | asd_init_sata(dev); | ||
278 | |||
279 | parent_ddb = (int) (unsigned long) dev->parent->lldd_dev; | ||
280 | asd_ddbsite_write_word(asd_ha, ddb, PARENT_DDB, parent_ddb); | ||
281 | pmtable_ddb = asd_ddbsite_read_word(asd_ha, parent_ddb, SISTER_DDB); | ||
282 | asd_ddbsite_write_word(asd_ha, pmtable_ddb, dev->sata_dev.port_no,ddb); | ||
283 | |||
284 | if (asd_ddbsite_read_byte(asd_ha, ddb, NUM_SATA_TAGS) > 0) { | ||
285 | i = asd_init_sata_tag_ddb(dev); | ||
286 | if (i < 0) { | ||
287 | asd_free_ddb(asd_ha, ddb); | ||
288 | return i; | ||
289 | } | ||
290 | } | ||
291 | return 0; | ||
292 | } | ||
293 | |||
294 | static int asd_init_initiator_ddb(struct domain_device *dev) | ||
295 | { | ||
296 | return -ENODEV; | ||
297 | } | ||
298 | |||
299 | /** | ||
300 | * asd_init_sata_pm_ddb -- SATA Port Multiplier | ||
301 | * dev: pointer to domain device | ||
302 | * | ||
303 | * For STP and direct-attached SATA Port Multipliers we need | ||
304 | * one target port DDB entry and one SATA PM table DDB entry. | ||
305 | */ | ||
306 | static int asd_init_sata_pm_ddb(struct domain_device *dev) | ||
307 | { | ||
308 | int res = 0; | ||
309 | |||
310 | res = asd_init_target_ddb(dev); | ||
311 | if (res) | ||
312 | goto out; | ||
313 | res = asd_init_sata_pm_table_ddb(dev); | ||
314 | if (res) | ||
315 | asd_free_ddb(dev->port->ha->lldd_ha, | ||
316 | (int) (unsigned long) dev->lldd_dev); | ||
317 | out: | ||
318 | return res; | ||
319 | } | ||
320 | |||
321 | int asd_dev_found(struct domain_device *dev) | ||
322 | { | ||
323 | int res = 0; | ||
324 | |||
325 | switch (dev->dev_type) { | ||
326 | case SATA_PM: | ||
327 | res = asd_init_sata_pm_ddb(dev); | ||
328 | break; | ||
329 | case SATA_PM_PORT: | ||
330 | res = asd_init_sata_pm_port_ddb(dev); | ||
331 | break; | ||
332 | default: | ||
333 | if (dev->tproto) | ||
334 | res = asd_init_target_ddb(dev); | ||
335 | else | ||
336 | res = asd_init_initiator_ddb(dev); | ||
337 | } | ||
338 | return res; | ||
339 | } | ||
340 | |||
341 | void asd_dev_gone(struct domain_device *dev) | ||
342 | { | ||
343 | int ddb, sister_ddb; | ||
344 | struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha; | ||
345 | |||
346 | ddb = (int) (unsigned long) dev->lldd_dev; | ||
347 | sister_ddb = asd_ddbsite_read_word(asd_ha, ddb, SISTER_DDB); | ||
348 | |||
349 | if (sister_ddb != 0xFFFF) | ||
350 | asd_free_ddb(asd_ha, sister_ddb); | ||
351 | asd_free_ddb(asd_ha, ddb); | ||
352 | dev->lldd_dev = NULL; | ||
353 | } | ||
diff --git a/drivers/scsi/aic94xx/aic94xx_dump.c b/drivers/scsi/aic94xx/aic94xx_dump.c new file mode 100644 index 000000000000..e6ade5996d95 --- /dev/null +++ b/drivers/scsi/aic94xx/aic94xx_dump.c | |||
@@ -0,0 +1,959 @@ | |||
1 | /* | ||
2 | * Aic94xx SAS/SATA driver dump interface. | ||
3 | * | ||
4 | * Copyright (C) 2004 Adaptec, Inc. All rights reserved. | ||
5 | * Copyright (C) 2004 David Chaw <david_chaw@adaptec.com> | ||
6 | * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> | ||
7 | * | ||
8 | * This file is licensed under GPLv2. | ||
9 | * | ||
10 | * This file is part of the aic94xx driver. | ||
11 | * | ||
12 | * The aic94xx driver is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License as | ||
14 | * published by the Free Software Foundation; version 2 of the | ||
15 | * License. | ||
16 | * | ||
17 | * The aic94xx driver is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
20 | * General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with the aic94xx driver; if not, write to the Free Software | ||
24 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
25 | * | ||
26 | * 2005/07/14/LT Complete overhaul of this file. Update pages, register | ||
27 | * locations, names, etc. Make use of macros. Print more information. | ||
28 | * Print all cseq and lseq mip and mdp. | ||
29 | * | ||
30 | */ | ||
31 | |||
32 | #include "linux/pci.h" | ||
33 | #include "aic94xx.h" | ||
34 | #include "aic94xx_reg.h" | ||
35 | #include "aic94xx_reg_def.h" | ||
36 | #include "aic94xx_sas.h" | ||
37 | |||
38 | #include "aic94xx_dump.h" | ||
39 | |||
40 | #ifdef ASD_DEBUG | ||
41 | |||
42 | #define MD(x) (1 << (x)) | ||
43 | #define MODE_COMMON (1 << 31) | ||
44 | #define MODE_0_7 (0xFF) | ||
45 | |||
46 | static const struct lseq_cio_regs { | ||
47 | char *name; | ||
48 | u32 offs; | ||
49 | u8 width; | ||
50 | u32 mode; | ||
51 | } LSEQmCIOREGS[] = { | ||
52 | {"LmMnSCBPTR", 0x20, 16, MD(0)|MD(1)|MD(2)|MD(3)|MD(4) }, | ||
53 | {"LmMnDDBPTR", 0x22, 16, MD(0)|MD(1)|MD(2)|MD(3)|MD(4) }, | ||
54 | {"LmREQMBX", 0x30, 32, MODE_COMMON }, | ||
55 | {"LmRSPMBX", 0x34, 32, MODE_COMMON }, | ||
56 | {"LmMnINT", 0x38, 32, MODE_0_7 }, | ||
57 | {"LmMnINTEN", 0x3C, 32, MODE_0_7 }, | ||
58 | {"LmXMTPRIMD", 0x40, 32, MODE_COMMON }, | ||
59 | {"LmXMTPRIMCS", 0x44, 8, MODE_COMMON }, | ||
60 | {"LmCONSTAT", 0x45, 8, MODE_COMMON }, | ||
61 | {"LmMnDMAERRS", 0x46, 8, MD(0)|MD(1) }, | ||
62 | {"LmMnSGDMAERRS", 0x47, 8, MD(0)|MD(1) }, | ||
63 | {"LmMnEXPHDRP", 0x48, 8, MD(0) }, | ||
64 | {"LmMnSASAALIGN", 0x48, 8, MD(1) }, | ||
65 | {"LmMnMSKHDRP", 0x49, 8, MD(0) }, | ||
66 | {"LmMnSTPALIGN", 0x49, 8, MD(1) }, | ||
67 | {"LmMnRCVHDRP", 0x4A, 8, MD(0) }, | ||
68 | {"LmMnXMTHDRP", 0x4A, 8, MD(1) }, | ||
69 | {"LmALIGNMODE", 0x4B, 8, MD(1) }, | ||
70 | {"LmMnEXPRCVCNT", 0x4C, 32, MD(0) }, | ||
71 | {"LmMnXMTCNT", 0x4C, 32, MD(1) }, | ||
72 | {"LmMnCURRTAG", 0x54, 16, MD(0) }, | ||
73 | {"LmMnPREVTAG", 0x56, 16, MD(0) }, | ||
74 | {"LmMnACKOFS", 0x58, 8, MD(1) }, | ||
75 | {"LmMnXFRLVL", 0x59, 8, MD(0)|MD(1) }, | ||
76 | {"LmMnSGDMACTL", 0x5A, 8, MD(0)|MD(1) }, | ||
77 | {"LmMnSGDMASTAT", 0x5B, 8, MD(0)|MD(1) }, | ||
78 | {"LmMnDDMACTL", 0x5C, 8, MD(0)|MD(1) }, | ||
79 | {"LmMnDDMASTAT", 0x5D, 8, MD(0)|MD(1) }, | ||
80 | {"LmMnDDMAMODE", 0x5E, 16, MD(0)|MD(1) }, | ||
81 | {"LmMnPIPECTL", 0x61, 8, MD(0)|MD(1) }, | ||
82 | {"LmMnACTSCB", 0x62, 16, MD(0)|MD(1) }, | ||
83 | {"LmMnSGBHADR", 0x64, 8, MD(0)|MD(1) }, | ||
84 | {"LmMnSGBADR", 0x65, 8, MD(0)|MD(1) }, | ||
85 | {"LmMnSGDCNT", 0x66, 8, MD(0)|MD(1) }, | ||
86 | {"LmMnSGDMADR", 0x68, 32, MD(0)|MD(1) }, | ||
87 | {"LmMnSGDMADR", 0x6C, 32, MD(0)|MD(1) }, | ||
88 | {"LmMnXFRCNT", 0x70, 32, MD(0)|MD(1) }, | ||
89 | {"LmMnXMTCRC", 0x74, 32, MD(1) }, | ||
90 | {"LmCURRTAG", 0x74, 16, MD(0) }, | ||
91 | {"LmPREVTAG", 0x76, 16, MD(0) }, | ||
92 | {"LmMnDPSEL", 0x7B, 8, MD(0)|MD(1) }, | ||
93 | {"LmDPTHSTAT", 0x7C, 8, MODE_COMMON }, | ||
94 | {"LmMnHOLDLVL", 0x7D, 8, MD(0) }, | ||
95 | {"LmMnSATAFS", 0x7E, 8, MD(1) }, | ||
96 | {"LmMnCMPLTSTAT", 0x7F, 8, MD(0)|MD(1) }, | ||
97 | {"LmPRMSTAT0", 0x80, 32, MODE_COMMON }, | ||
98 | {"LmPRMSTAT1", 0x84, 32, MODE_COMMON }, | ||
99 | {"LmGPRMINT", 0x88, 8, MODE_COMMON }, | ||
100 | {"LmMnCURRSCB", 0x8A, 16, MD(0) }, | ||
101 | {"LmPRMICODE", 0x8C, 32, MODE_COMMON }, | ||
102 | {"LmMnRCVCNT", 0x90, 16, MD(0) }, | ||
103 | {"LmMnBUFSTAT", 0x92, 16, MD(0) }, | ||
104 | {"LmMnXMTHDRSIZE",0x92, 8, MD(1) }, | ||
105 | {"LmMnXMTSIZE", 0x93, 8, MD(1) }, | ||
106 | {"LmMnTGTXFRCNT", 0x94, 32, MD(0) }, | ||
107 | {"LmMnEXPROFS", 0x98, 32, MD(0) }, | ||
108 | {"LmMnXMTROFS", 0x98, 32, MD(1) }, | ||
109 | {"LmMnRCVROFS", 0x9C, 32, MD(0) }, | ||
110 | {"LmCONCTL", 0xA0, 16, MODE_COMMON }, | ||
111 | {"LmBITLTIMER", 0xA2, 16, MODE_COMMON }, | ||
112 | {"LmWWNLOW", 0xA8, 32, MODE_COMMON }, | ||
113 | {"LmWWNHIGH", 0xAC, 32, MODE_COMMON }, | ||
114 | {"LmMnFRMERR", 0xB0, 32, MD(0) }, | ||
115 | {"LmMnFRMERREN", 0xB4, 32, MD(0) }, | ||
116 | {"LmAWTIMER", 0xB8, 16, MODE_COMMON }, | ||
117 | {"LmAWTCTL", 0xBA, 8, MODE_COMMON }, | ||
118 | {"LmMnHDRCMPS", 0xC0, 32, MD(0) }, | ||
119 | {"LmMnXMTSTAT", 0xC4, 8, MD(1) }, | ||
120 | {"LmHWTSTATEN", 0xC5, 8, MODE_COMMON }, | ||
121 | {"LmMnRRDYRC", 0xC6, 8, MD(0) }, | ||
122 | {"LmMnRRDYTC", 0xC6, 8, MD(1) }, | ||
123 | {"LmHWTSTAT", 0xC7, 8, MODE_COMMON }, | ||
124 | {"LmMnDATABUFADR",0xC8, 16, MD(0)|MD(1) }, | ||
125 | {"LmDWSSTATUS", 0xCB, 8, MODE_COMMON }, | ||
126 | {"LmMnACTSTAT", 0xCE, 16, MD(0)|MD(1) }, | ||
127 | {"LmMnREQSCB", 0xD2, 16, MD(0)|MD(1) }, | ||
128 | {"LmXXXPRIM", 0xD4, 32, MODE_COMMON }, | ||
129 | {"LmRCVASTAT", 0xD9, 8, MODE_COMMON }, | ||
130 | {"LmINTDIS1", 0xDA, 8, MODE_COMMON }, | ||
131 | {"LmPSTORESEL", 0xDB, 8, MODE_COMMON }, | ||
132 | {"LmPSTORE", 0xDC, 32, MODE_COMMON }, | ||
133 | {"LmPRIMSTAT0EN", 0xE0, 32, MODE_COMMON }, | ||
134 | {"LmPRIMSTAT1EN", 0xE4, 32, MODE_COMMON }, | ||
135 | {"LmDONETCTL", 0xF2, 16, MODE_COMMON }, | ||
136 | {NULL, 0, 0, 0 } | ||
137 | }; | ||
138 | /* | ||
139 | static struct lseq_cio_regs LSEQmOOBREGS[] = { | ||
140 | {"OOB_BFLTR" ,0x100, 8, MD(5)}, | ||
141 | {"OOB_INIT_MIN" ,0x102,16, MD(5)}, | ||
142 | {"OOB_INIT_MAX" ,0x104,16, MD(5)}, | ||
143 | {"OOB_INIT_NEG" ,0x106,16, MD(5)}, | ||
144 | {"OOB_SAS_MIN" ,0x108,16, MD(5)}, | ||
145 | {"OOB_SAS_MAX" ,0x10A,16, MD(5)}, | ||
146 | {"OOB_SAS_NEG" ,0x10C,16, MD(5)}, | ||
147 | {"OOB_WAKE_MIN" ,0x10E,16, MD(5)}, | ||
148 | {"OOB_WAKE_MAX" ,0x110,16, MD(5)}, | ||
149 | {"OOB_WAKE_NEG" ,0x112,16, MD(5)}, | ||
150 | {"OOB_IDLE_MAX" ,0x114,16, MD(5)}, | ||
151 | {"OOB_BURST_MAX" ,0x116,16, MD(5)}, | ||
152 | {"OOB_XMIT_BURST" ,0x118, 8, MD(5)}, | ||
153 | {"OOB_SEND_PAIRS" ,0x119, 8, MD(5)}, | ||
154 | {"OOB_INIT_IDLE" ,0x11A, 8, MD(5)}, | ||
155 | {"OOB_INIT_NEGO" ,0x11C, 8, MD(5)}, | ||
156 | {"OOB_SAS_IDLE" ,0x11E, 8, MD(5)}, | ||
157 | {"OOB_SAS_NEGO" ,0x120, 8, MD(5)}, | ||
158 | {"OOB_WAKE_IDLE" ,0x122, 8, MD(5)}, | ||
159 | {"OOB_WAKE_NEGO" ,0x124, 8, MD(5)}, | ||
160 | {"OOB_DATA_KBITS" ,0x126, 8, MD(5)}, | ||
161 | {"OOB_BURST_DATA" ,0x128,32, MD(5)}, | ||
162 | {"OOB_ALIGN_0_DATA" ,0x12C,32, MD(5)}, | ||
163 | {"OOB_ALIGN_1_DATA" ,0x130,32, MD(5)}, | ||
164 | {"OOB_SYNC_DATA" ,0x134,32, MD(5)}, | ||
165 | {"OOB_D10_2_DATA" ,0x138,32, MD(5)}, | ||
166 | {"OOB_PHY_RST_CNT" ,0x13C,32, MD(5)}, | ||
167 | {"OOB_SIG_GEN" ,0x140, 8, MD(5)}, | ||
168 | {"OOB_XMIT" ,0x141, 8, MD(5)}, | ||
169 | {"FUNCTION_MAKS" ,0x142, 8, MD(5)}, | ||
170 | {"OOB_MODE" ,0x143, 8, MD(5)}, | ||
171 | {"CURRENT_STATUS" ,0x144, 8, MD(5)}, | ||
172 | {"SPEED_MASK" ,0x145, 8, MD(5)}, | ||
173 | {"PRIM_COUNT" ,0x146, 8, MD(5)}, | ||
174 | {"OOB_SIGNALS" ,0x148, 8, MD(5)}, | ||
175 | {"OOB_DATA_DET" ,0x149, 8, MD(5)}, | ||
176 | {"OOB_TIME_OUT" ,0x14C, 8, MD(5)}, | ||
177 | {"OOB_TIMER_ENABLE" ,0x14D, 8, MD(5)}, | ||
178 | {"OOB_STATUS" ,0x14E, 8, MD(5)}, | ||
179 | {"HOT_PLUG_DELAY" ,0x150, 8, MD(5)}, | ||
180 | {"RCD_DELAY" ,0x151, 8, MD(5)}, | ||
181 | {"COMSAS_TIMER" ,0x152, 8, MD(5)}, | ||
182 | {"SNTT_DELAY" ,0x153, 8, MD(5)}, | ||
183 | {"SPD_CHNG_DELAY" ,0x154, 8, MD(5)}, | ||
184 | {"SNLT_DELAY" ,0x155, 8, MD(5)}, | ||
185 | {"SNWT_DELAY" ,0x156, 8, MD(5)}, | ||
186 | {"ALIGN_DELAY" ,0x157, 8, MD(5)}, | ||
187 | {"INT_ENABLE_0" ,0x158, 8, MD(5)}, | ||
188 | {"INT_ENABLE_1" ,0x159, 8, MD(5)}, | ||
189 | {"INT_ENABLE_2" ,0x15A, 8, MD(5)}, | ||
190 | {"INT_ENABLE_3" ,0x15B, 8, MD(5)}, | ||
191 | {"OOB_TEST_REG" ,0x15C, 8, MD(5)}, | ||
192 | {"PHY_CONTROL_0" ,0x160, 8, MD(5)}, | ||
193 | {"PHY_CONTROL_1" ,0x161, 8, MD(5)}, | ||
194 | {"PHY_CONTROL_2" ,0x162, 8, MD(5)}, | ||
195 | {"PHY_CONTROL_3" ,0x163, 8, MD(5)}, | ||
196 | {"PHY_OOB_CAL_TX" ,0x164, 8, MD(5)}, | ||
197 | {"PHY_OOB_CAL_RX" ,0x165, 8, MD(5)}, | ||
198 | {"OOB_PHY_CAL_TX" ,0x166, 8, MD(5)}, | ||
199 | {"OOB_PHY_CAL_RX" ,0x167, 8, MD(5)}, | ||
200 | {"PHY_CONTROL_4" ,0x168, 8, MD(5)}, | ||
201 | {"PHY_TEST" ,0x169, 8, MD(5)}, | ||
202 | {"PHY_PWR_CTL" ,0x16A, 8, MD(5)}, | ||
203 | {"PHY_PWR_DELAY" ,0x16B, 8, MD(5)}, | ||
204 | {"OOB_SM_CON" ,0x16C, 8, MD(5)}, | ||
205 | {"ADDR_TRAP_1" ,0x16D, 8, MD(5)}, | ||
206 | {"ADDR_NEXT_1" ,0x16E, 8, MD(5)}, | ||
207 | {"NEXT_ST_1" ,0x16F, 8, MD(5)}, | ||
208 | {"OOB_SM_STATE" ,0x170, 8, MD(5)}, | ||
209 | {"ADDR_TRAP_2" ,0x171, 8, MD(5)}, | ||
210 | {"ADDR_NEXT_2" ,0x172, 8, MD(5)}, | ||
211 | {"NEXT_ST_2" ,0x173, 8, MD(5)}, | ||
212 | {NULL, 0, 0, 0 } | ||
213 | }; | ||
214 | */ | ||
215 | #define STR_8BIT " %30s[0x%04x]:0x%02x\n" | ||
216 | #define STR_16BIT " %30s[0x%04x]:0x%04x\n" | ||
217 | #define STR_32BIT " %30s[0x%04x]:0x%08x\n" | ||
218 | #define STR_64BIT " %30s[0x%04x]:0x%llx\n" | ||
219 | |||
220 | #define PRINT_REG_8bit(_ha, _n, _r) asd_printk(STR_8BIT, #_n, _n, \ | ||
221 | asd_read_reg_byte(_ha, _r)) | ||
222 | #define PRINT_REG_16bit(_ha, _n, _r) asd_printk(STR_16BIT, #_n, _n, \ | ||
223 | asd_read_reg_word(_ha, _r)) | ||
224 | #define PRINT_REG_32bit(_ha, _n, _r) asd_printk(STR_32BIT, #_n, _n, \ | ||
225 | asd_read_reg_dword(_ha, _r)) | ||
226 | |||
227 | #define PRINT_CREG_8bit(_ha, _n) asd_printk(STR_8BIT, #_n, _n, \ | ||
228 | asd_read_reg_byte(_ha, C##_n)) | ||
229 | #define PRINT_CREG_16bit(_ha, _n) asd_printk(STR_16BIT, #_n, _n, \ | ||
230 | asd_read_reg_word(_ha, C##_n)) | ||
231 | #define PRINT_CREG_32bit(_ha, _n) asd_printk(STR_32BIT, #_n, _n, \ | ||
232 | asd_read_reg_dword(_ha, C##_n)) | ||
233 | |||
234 | #define MSTR_8BIT " Mode:%02d %30s[0x%04x]:0x%02x\n" | ||
235 | #define MSTR_16BIT " Mode:%02d %30s[0x%04x]:0x%04x\n" | ||
236 | #define MSTR_32BIT " Mode:%02d %30s[0x%04x]:0x%08x\n" | ||
237 | |||
238 | #define PRINT_MREG_8bit(_ha, _m, _n, _r) asd_printk(MSTR_8BIT, _m, #_n, _n, \ | ||
239 | asd_read_reg_byte(_ha, _r)) | ||
240 | #define PRINT_MREG_16bit(_ha, _m, _n, _r) asd_printk(MSTR_16BIT, _m, #_n, _n, \ | ||
241 | asd_read_reg_word(_ha, _r)) | ||
242 | #define PRINT_MREG_32bit(_ha, _m, _n, _r) asd_printk(MSTR_32BIT, _m, #_n, _n, \ | ||
243 | asd_read_reg_dword(_ha, _r)) | ||
244 | |||
245 | /* can also be used for MD when the register is mode aware already */ | ||
246 | #define PRINT_MIS_byte(_ha, _n) asd_printk(STR_8BIT, #_n,CSEQ_##_n-CMAPPEDSCR,\ | ||
247 | asd_read_reg_byte(_ha, CSEQ_##_n)) | ||
248 | #define PRINT_MIS_word(_ha, _n) asd_printk(STR_16BIT,#_n,CSEQ_##_n-CMAPPEDSCR,\ | ||
249 | asd_read_reg_word(_ha, CSEQ_##_n)) | ||
250 | #define PRINT_MIS_dword(_ha, _n) \ | ||
251 | asd_printk(STR_32BIT,#_n,CSEQ_##_n-CMAPPEDSCR,\ | ||
252 | asd_read_reg_dword(_ha, CSEQ_##_n)) | ||
253 | #define PRINT_MIS_qword(_ha, _n) \ | ||
254 | asd_printk(STR_64BIT, #_n,CSEQ_##_n-CMAPPEDSCR, \ | ||
255 | (unsigned long long)(((u64)asd_read_reg_dword(_ha, CSEQ_##_n)) \ | ||
256 | | (((u64)asd_read_reg_dword(_ha, (CSEQ_##_n)+4))<<32))) | ||
257 | |||
258 | #define CMDP_REG(_n, _m) (_m*(CSEQ_PAGE_SIZE*2)+CSEQ_##_n) | ||
259 | #define PRINT_CMDP_word(_ha, _n) \ | ||
260 | asd_printk("%20s 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x\n", \ | ||
261 | #_n, \ | ||
262 | asd_read_reg_word(_ha, CMDP_REG(_n, 0)), \ | ||
263 | asd_read_reg_word(_ha, CMDP_REG(_n, 1)), \ | ||
264 | asd_read_reg_word(_ha, CMDP_REG(_n, 2)), \ | ||
265 | asd_read_reg_word(_ha, CMDP_REG(_n, 3)), \ | ||
266 | asd_read_reg_word(_ha, CMDP_REG(_n, 4)), \ | ||
267 | asd_read_reg_word(_ha, CMDP_REG(_n, 5)), \ | ||
268 | asd_read_reg_word(_ha, CMDP_REG(_n, 6)), \ | ||
269 | asd_read_reg_word(_ha, CMDP_REG(_n, 7))) | ||
270 | |||
271 | #define PRINT_CMDP_byte(_ha, _n) \ | ||
272 | asd_printk("%20s 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x 0x%04x\n", \ | ||
273 | #_n, \ | ||
274 | asd_read_reg_byte(_ha, CMDP_REG(_n, 0)), \ | ||
275 | asd_read_reg_byte(_ha, CMDP_REG(_n, 1)), \ | ||
276 | asd_read_reg_byte(_ha, CMDP_REG(_n, 2)), \ | ||
277 | asd_read_reg_byte(_ha, CMDP_REG(_n, 3)), \ | ||
278 | asd_read_reg_byte(_ha, CMDP_REG(_n, 4)), \ | ||
279 | asd_read_reg_byte(_ha, CMDP_REG(_n, 5)), \ | ||
280 | asd_read_reg_byte(_ha, CMDP_REG(_n, 6)), \ | ||
281 | asd_read_reg_byte(_ha, CMDP_REG(_n, 7))) | ||
282 | |||
283 | static void asd_dump_cseq_state(struct asd_ha_struct *asd_ha) | ||
284 | { | ||
285 | int mode; | ||
286 | |||
287 | asd_printk("CSEQ STATE\n"); | ||
288 | |||
289 | asd_printk("ARP2 REGISTERS\n"); | ||
290 | |||
291 | PRINT_CREG_32bit(asd_ha, ARP2CTL); | ||
292 | PRINT_CREG_32bit(asd_ha, ARP2INT); | ||
293 | PRINT_CREG_32bit(asd_ha, ARP2INTEN); | ||
294 | PRINT_CREG_8bit(asd_ha, MODEPTR); | ||
295 | PRINT_CREG_8bit(asd_ha, ALTMODE); | ||
296 | PRINT_CREG_8bit(asd_ha, FLAG); | ||
297 | PRINT_CREG_8bit(asd_ha, ARP2INTCTL); | ||
298 | PRINT_CREG_16bit(asd_ha, STACK); | ||
299 | PRINT_CREG_16bit(asd_ha, PRGMCNT); | ||
300 | PRINT_CREG_16bit(asd_ha, ACCUM); | ||
301 | PRINT_CREG_16bit(asd_ha, SINDEX); | ||
302 | PRINT_CREG_16bit(asd_ha, DINDEX); | ||
303 | PRINT_CREG_8bit(asd_ha, SINDIR); | ||
304 | PRINT_CREG_8bit(asd_ha, DINDIR); | ||
305 | PRINT_CREG_8bit(asd_ha, JUMLDIR); | ||
306 | PRINT_CREG_8bit(asd_ha, ARP2HALTCODE); | ||
307 | PRINT_CREG_16bit(asd_ha, CURRADDR); | ||
308 | PRINT_CREG_16bit(asd_ha, LASTADDR); | ||
309 | PRINT_CREG_16bit(asd_ha, NXTLADDR); | ||
310 | |||
311 | asd_printk("IOP REGISTERS\n"); | ||
312 | |||
313 | PRINT_REG_32bit(asd_ha, BISTCTL1, CBISTCTL); | ||
314 | PRINT_CREG_32bit(asd_ha, MAPPEDSCR); | ||
315 | |||
316 | asd_printk("CIO REGISTERS\n"); | ||
317 | |||
318 | for (mode = 0; mode < 9; mode++) | ||
319 | PRINT_MREG_16bit(asd_ha, mode, MnSCBPTR, CMnSCBPTR(mode)); | ||
320 | PRINT_MREG_16bit(asd_ha, 15, MnSCBPTR, CMnSCBPTR(15)); | ||
321 | |||
322 | for (mode = 0; mode < 9; mode++) | ||
323 | PRINT_MREG_16bit(asd_ha, mode, MnDDBPTR, CMnDDBPTR(mode)); | ||
324 | PRINT_MREG_16bit(asd_ha, 15, MnDDBPTR, CMnDDBPTR(15)); | ||
325 | |||
326 | for (mode = 0; mode < 8; mode++) | ||
327 | PRINT_MREG_32bit(asd_ha, mode, MnREQMBX, CMnREQMBX(mode)); | ||
328 | for (mode = 0; mode < 8; mode++) | ||
329 | PRINT_MREG_32bit(asd_ha, mode, MnRSPMBX, CMnRSPMBX(mode)); | ||
330 | for (mode = 0; mode < 8; mode++) | ||
331 | PRINT_MREG_32bit(asd_ha, mode, MnINT, CMnINT(mode)); | ||
332 | for (mode = 0; mode < 8; mode++) | ||
333 | PRINT_MREG_32bit(asd_ha, mode, MnINTEN, CMnINTEN(mode)); | ||
334 | |||
335 | PRINT_CREG_8bit(asd_ha, SCRATCHPAGE); | ||
336 | for (mode = 0; mode < 8; mode++) | ||
337 | PRINT_MREG_8bit(asd_ha, mode, MnSCRATCHPAGE, | ||
338 | CMnSCRATCHPAGE(mode)); | ||
339 | |||
340 | PRINT_REG_32bit(asd_ha, CLINKCON, CLINKCON); | ||
341 | PRINT_REG_8bit(asd_ha, CCONMSK, CCONMSK); | ||
342 | PRINT_REG_8bit(asd_ha, CCONEXIST, CCONEXIST); | ||
343 | PRINT_REG_16bit(asd_ha, CCONMODE, CCONMODE); | ||
344 | PRINT_REG_32bit(asd_ha, CTIMERCALC, CTIMERCALC); | ||
345 | PRINT_REG_8bit(asd_ha, CINTDIS, CINTDIS); | ||
346 | |||
347 | asd_printk("SCRATCH MEMORY\n"); | ||
348 | |||
349 | asd_printk("MIP 4 >>>>>\n"); | ||
350 | PRINT_MIS_word(asd_ha, Q_EXE_HEAD); | ||
351 | PRINT_MIS_word(asd_ha, Q_EXE_TAIL); | ||
352 | PRINT_MIS_word(asd_ha, Q_DONE_HEAD); | ||
353 | PRINT_MIS_word(asd_ha, Q_DONE_TAIL); | ||
354 | PRINT_MIS_word(asd_ha, Q_SEND_HEAD); | ||
355 | PRINT_MIS_word(asd_ha, Q_SEND_TAIL); | ||
356 | PRINT_MIS_word(asd_ha, Q_DMA2CHIM_HEAD); | ||
357 | PRINT_MIS_word(asd_ha, Q_DMA2CHIM_TAIL); | ||
358 | PRINT_MIS_word(asd_ha, Q_COPY_HEAD); | ||
359 | PRINT_MIS_word(asd_ha, Q_COPY_TAIL); | ||
360 | PRINT_MIS_word(asd_ha, REG0); | ||
361 | PRINT_MIS_word(asd_ha, REG1); | ||
362 | PRINT_MIS_dword(asd_ha, REG2); | ||
363 | PRINT_MIS_byte(asd_ha, LINK_CTL_Q_MAP); | ||
364 | PRINT_MIS_byte(asd_ha, MAX_CSEQ_MODE); | ||
365 | PRINT_MIS_byte(asd_ha, FREE_LIST_HACK_COUNT); | ||
366 | |||
367 | asd_printk("MIP 5 >>>>\n"); | ||
368 | PRINT_MIS_qword(asd_ha, EST_NEXUS_REQ_QUEUE); | ||
369 | PRINT_MIS_qword(asd_ha, EST_NEXUS_REQ_COUNT); | ||
370 | PRINT_MIS_word(asd_ha, Q_EST_NEXUS_HEAD); | ||
371 | PRINT_MIS_word(asd_ha, Q_EST_NEXUS_TAIL); | ||
372 | PRINT_MIS_word(asd_ha, NEED_EST_NEXUS_SCB); | ||
373 | PRINT_MIS_byte(asd_ha, EST_NEXUS_REQ_HEAD); | ||
374 | PRINT_MIS_byte(asd_ha, EST_NEXUS_REQ_TAIL); | ||
375 | PRINT_MIS_byte(asd_ha, EST_NEXUS_SCB_OFFSET); | ||
376 | |||
377 | asd_printk("MIP 6 >>>>\n"); | ||
378 | PRINT_MIS_word(asd_ha, INT_ROUT_RET_ADDR0); | ||
379 | PRINT_MIS_word(asd_ha, INT_ROUT_RET_ADDR1); | ||
380 | PRINT_MIS_word(asd_ha, INT_ROUT_SCBPTR); | ||
381 | PRINT_MIS_byte(asd_ha, INT_ROUT_MODE); | ||
382 | PRINT_MIS_byte(asd_ha, ISR_SCRATCH_FLAGS); | ||
383 | PRINT_MIS_word(asd_ha, ISR_SAVE_SINDEX); | ||
384 | PRINT_MIS_word(asd_ha, ISR_SAVE_DINDEX); | ||
385 | PRINT_MIS_word(asd_ha, Q_MONIRTT_HEAD); | ||
386 | PRINT_MIS_word(asd_ha, Q_MONIRTT_TAIL); | ||
387 | PRINT_MIS_byte(asd_ha, FREE_SCB_MASK); | ||
388 | PRINT_MIS_word(asd_ha, BUILTIN_FREE_SCB_HEAD); | ||
389 | PRINT_MIS_word(asd_ha, BUILTIN_FREE_SCB_TAIL); | ||
390 | PRINT_MIS_word(asd_ha, EXTENDED_FREE_SCB_HEAD); | ||
391 | PRINT_MIS_word(asd_ha, EXTENDED_FREE_SCB_TAIL); | ||
392 | |||
393 | asd_printk("MIP 7 >>>>\n"); | ||
394 | PRINT_MIS_qword(asd_ha, EMPTY_REQ_QUEUE); | ||
395 | PRINT_MIS_qword(asd_ha, EMPTY_REQ_COUNT); | ||
396 | PRINT_MIS_word(asd_ha, Q_EMPTY_HEAD); | ||
397 | PRINT_MIS_word(asd_ha, Q_EMPTY_TAIL); | ||
398 | PRINT_MIS_word(asd_ha, NEED_EMPTY_SCB); | ||
399 | PRINT_MIS_byte(asd_ha, EMPTY_REQ_HEAD); | ||
400 | PRINT_MIS_byte(asd_ha, EMPTY_REQ_TAIL); | ||
401 | PRINT_MIS_byte(asd_ha, EMPTY_SCB_OFFSET); | ||
402 | PRINT_MIS_word(asd_ha, PRIMITIVE_DATA); | ||
403 | PRINT_MIS_dword(asd_ha, TIMEOUT_CONST); | ||
404 | |||
405 | asd_printk("MDP 0 >>>>\n"); | ||
406 | asd_printk("%-20s %6s %6s %6s %6s %6s %6s %6s %6s\n", | ||
407 | "Mode: ", "0", "1", "2", "3", "4", "5", "6", "7"); | ||
408 | PRINT_CMDP_word(asd_ha, LRM_SAVE_SINDEX); | ||
409 | PRINT_CMDP_word(asd_ha, LRM_SAVE_SCBPTR); | ||
410 | PRINT_CMDP_word(asd_ha, Q_LINK_HEAD); | ||
411 | PRINT_CMDP_word(asd_ha, Q_LINK_TAIL); | ||
412 | PRINT_CMDP_byte(asd_ha, LRM_SAVE_SCRPAGE); | ||
413 | |||
414 | asd_printk("MDP 0 Mode 8 >>>>\n"); | ||
415 | PRINT_MIS_word(asd_ha, RET_ADDR); | ||
416 | PRINT_MIS_word(asd_ha, RET_SCBPTR); | ||
417 | PRINT_MIS_word(asd_ha, SAVE_SCBPTR); | ||
418 | PRINT_MIS_word(asd_ha, EMPTY_TRANS_CTX); | ||
419 | PRINT_MIS_word(asd_ha, RESP_LEN); | ||
420 | PRINT_MIS_word(asd_ha, TMF_SCBPTR); | ||
421 | PRINT_MIS_word(asd_ha, GLOBAL_PREV_SCB); | ||
422 | PRINT_MIS_word(asd_ha, GLOBAL_HEAD); | ||
423 | PRINT_MIS_word(asd_ha, CLEAR_LU_HEAD); | ||
424 | PRINT_MIS_byte(asd_ha, TMF_OPCODE); | ||
425 | PRINT_MIS_byte(asd_ha, SCRATCH_FLAGS); | ||
426 | PRINT_MIS_word(asd_ha, HSB_SITE); | ||
427 | PRINT_MIS_word(asd_ha, FIRST_INV_SCB_SITE); | ||
428 | PRINT_MIS_word(asd_ha, FIRST_INV_DDB_SITE); | ||
429 | |||
430 | asd_printk("MDP 1 Mode 8 >>>>\n"); | ||
431 | PRINT_MIS_qword(asd_ha, LUN_TO_CLEAR); | ||
432 | PRINT_MIS_qword(asd_ha, LUN_TO_CHECK); | ||
433 | |||
434 | asd_printk("MDP 2 Mode 8 >>>>\n"); | ||
435 | PRINT_MIS_qword(asd_ha, HQ_NEW_POINTER); | ||
436 | PRINT_MIS_qword(asd_ha, HQ_DONE_BASE); | ||
437 | PRINT_MIS_dword(asd_ha, HQ_DONE_POINTER); | ||
438 | PRINT_MIS_byte(asd_ha, HQ_DONE_PASS); | ||
439 | } | ||
440 | |||
441 | #define PRINT_LREG_8bit(_h, _lseq, _n) \ | ||
442 | asd_printk(STR_8BIT, #_n, _n, asd_read_reg_byte(_h, Lm##_n(_lseq))) | ||
443 | #define PRINT_LREG_16bit(_h, _lseq, _n) \ | ||
444 | asd_printk(STR_16BIT, #_n, _n, asd_read_reg_word(_h, Lm##_n(_lseq))) | ||
445 | #define PRINT_LREG_32bit(_h, _lseq, _n) \ | ||
446 | asd_printk(STR_32BIT, #_n, _n, asd_read_reg_dword(_h, Lm##_n(_lseq))) | ||
447 | |||
448 | #define PRINT_LMIP_byte(_h, _lseq, _n) \ | ||
449 | asd_printk(STR_8BIT, #_n, LmSEQ_##_n(_lseq)-LmSCRATCH(_lseq), \ | ||
450 | asd_read_reg_byte(_h, LmSEQ_##_n(_lseq))) | ||
451 | #define PRINT_LMIP_word(_h, _lseq, _n) \ | ||
452 | asd_printk(STR_16BIT, #_n, LmSEQ_##_n(_lseq)-LmSCRATCH(_lseq), \ | ||
453 | asd_read_reg_word(_h, LmSEQ_##_n(_lseq))) | ||
454 | #define PRINT_LMIP_dword(_h, _lseq, _n) \ | ||
455 | asd_printk(STR_32BIT, #_n, LmSEQ_##_n(_lseq)-LmSCRATCH(_lseq), \ | ||
456 | asd_read_reg_dword(_h, LmSEQ_##_n(_lseq))) | ||
457 | #define PRINT_LMIP_qword(_h, _lseq, _n) \ | ||
458 | asd_printk(STR_64BIT, #_n, LmSEQ_##_n(_lseq)-LmSCRATCH(_lseq), \ | ||
459 | (unsigned long long)(((unsigned long long) \ | ||
460 | asd_read_reg_dword(_h, LmSEQ_##_n(_lseq))) \ | ||
461 | | (((unsigned long long) \ | ||
462 | asd_read_reg_dword(_h, LmSEQ_##_n(_lseq)+4))<<32))) | ||
463 | |||
464 | static void asd_print_lseq_cio_reg(struct asd_ha_struct *asd_ha, | ||
465 | u32 lseq_cio_addr, int i) | ||
466 | { | ||
467 | switch (LSEQmCIOREGS[i].width) { | ||
468 | case 8: | ||
469 | asd_printk("%20s[0x%x]: 0x%02x\n", LSEQmCIOREGS[i].name, | ||
470 | LSEQmCIOREGS[i].offs, | ||
471 | asd_read_reg_byte(asd_ha, lseq_cio_addr + | ||
472 | LSEQmCIOREGS[i].offs)); | ||
473 | |||
474 | break; | ||
475 | case 16: | ||
476 | asd_printk("%20s[0x%x]: 0x%04x\n", LSEQmCIOREGS[i].name, | ||
477 | LSEQmCIOREGS[i].offs, | ||
478 | asd_read_reg_word(asd_ha, lseq_cio_addr + | ||
479 | LSEQmCIOREGS[i].offs)); | ||
480 | |||
481 | break; | ||
482 | case 32: | ||
483 | asd_printk("%20s[0x%x]: 0x%08x\n", LSEQmCIOREGS[i].name, | ||
484 | LSEQmCIOREGS[i].offs, | ||
485 | asd_read_reg_dword(asd_ha, lseq_cio_addr + | ||
486 | LSEQmCIOREGS[i].offs)); | ||
487 | break; | ||
488 | } | ||
489 | } | ||
490 | |||
491 | static void asd_dump_lseq_state(struct asd_ha_struct *asd_ha, int lseq) | ||
492 | { | ||
493 | u32 moffs; | ||
494 | int mode; | ||
495 | |||
496 | asd_printk("LSEQ %d STATE\n", lseq); | ||
497 | |||
498 | asd_printk("LSEQ%d: ARP2 REGISTERS\n", lseq); | ||
499 | PRINT_LREG_32bit(asd_ha, lseq, ARP2CTL); | ||
500 | PRINT_LREG_32bit(asd_ha, lseq, ARP2INT); | ||
501 | PRINT_LREG_32bit(asd_ha, lseq, ARP2INTEN); | ||
502 | PRINT_LREG_8bit(asd_ha, lseq, MODEPTR); | ||
503 | PRINT_LREG_8bit(asd_ha, lseq, ALTMODE); | ||
504 | PRINT_LREG_8bit(asd_ha, lseq, FLAG); | ||
505 | PRINT_LREG_8bit(asd_ha, lseq, ARP2INTCTL); | ||
506 | PRINT_LREG_16bit(asd_ha, lseq, STACK); | ||
507 | PRINT_LREG_16bit(asd_ha, lseq, PRGMCNT); | ||
508 | PRINT_LREG_16bit(asd_ha, lseq, ACCUM); | ||
509 | PRINT_LREG_16bit(asd_ha, lseq, SINDEX); | ||
510 | PRINT_LREG_16bit(asd_ha, lseq, DINDEX); | ||
511 | PRINT_LREG_8bit(asd_ha, lseq, SINDIR); | ||
512 | PRINT_LREG_8bit(asd_ha, lseq, DINDIR); | ||
513 | PRINT_LREG_8bit(asd_ha, lseq, JUMLDIR); | ||
514 | PRINT_LREG_8bit(asd_ha, lseq, ARP2HALTCODE); | ||
515 | PRINT_LREG_16bit(asd_ha, lseq, CURRADDR); | ||
516 | PRINT_LREG_16bit(asd_ha, lseq, LASTADDR); | ||
517 | PRINT_LREG_16bit(asd_ha, lseq, NXTLADDR); | ||
518 | |||
519 | asd_printk("LSEQ%d: IOP REGISTERS\n", lseq); | ||
520 | |||
521 | PRINT_LREG_32bit(asd_ha, lseq, MODECTL); | ||
522 | PRINT_LREG_32bit(asd_ha, lseq, DBGMODE); | ||
523 | PRINT_LREG_32bit(asd_ha, lseq, CONTROL); | ||
524 | PRINT_REG_32bit(asd_ha, BISTCTL0, LmBISTCTL0(lseq)); | ||
525 | PRINT_REG_32bit(asd_ha, BISTCTL1, LmBISTCTL1(lseq)); | ||
526 | |||
527 | asd_printk("LSEQ%d: CIO REGISTERS\n", lseq); | ||
528 | asd_printk("Mode common:\n"); | ||
529 | |||
530 | for (mode = 0; mode < 8; mode++) { | ||
531 | u32 lseq_cio_addr = LmSEQ_PHY_BASE(mode, lseq); | ||
532 | int i; | ||
533 | |||
534 | for (i = 0; LSEQmCIOREGS[i].name; i++) | ||
535 | if (LSEQmCIOREGS[i].mode == MODE_COMMON) | ||
536 | asd_print_lseq_cio_reg(asd_ha,lseq_cio_addr,i); | ||
537 | } | ||
538 | |||
539 | asd_printk("Mode unique:\n"); | ||
540 | for (mode = 0; mode < 8; mode++) { | ||
541 | u32 lseq_cio_addr = LmSEQ_PHY_BASE(mode, lseq); | ||
542 | int i; | ||
543 | |||
544 | asd_printk("Mode %d\n", mode); | ||
545 | for (i = 0; LSEQmCIOREGS[i].name; i++) { | ||
546 | if (!(LSEQmCIOREGS[i].mode & (1 << mode))) | ||
547 | continue; | ||
548 | asd_print_lseq_cio_reg(asd_ha, lseq_cio_addr, i); | ||
549 | } | ||
550 | } | ||
551 | |||
552 | asd_printk("SCRATCH MEMORY\n"); | ||
553 | |||
554 | asd_printk("LSEQ%d MIP 0 >>>>\n", lseq); | ||
555 | PRINT_LMIP_word(asd_ha, lseq, Q_TGTXFR_HEAD); | ||
556 | PRINT_LMIP_word(asd_ha, lseq, Q_TGTXFR_TAIL); | ||
557 | PRINT_LMIP_byte(asd_ha, lseq, LINK_NUMBER); | ||
558 | PRINT_LMIP_byte(asd_ha, lseq, SCRATCH_FLAGS); | ||
559 | PRINT_LMIP_qword(asd_ha, lseq, CONNECTION_STATE); | ||
560 | PRINT_LMIP_word(asd_ha, lseq, CONCTL); | ||
561 | PRINT_LMIP_byte(asd_ha, lseq, CONSTAT); | ||
562 | PRINT_LMIP_byte(asd_ha, lseq, CONNECTION_MODES); | ||
563 | PRINT_LMIP_word(asd_ha, lseq, REG1_ISR); | ||
564 | PRINT_LMIP_word(asd_ha, lseq, REG2_ISR); | ||
565 | PRINT_LMIP_word(asd_ha, lseq, REG3_ISR); | ||
566 | PRINT_LMIP_qword(asd_ha, lseq,REG0_ISR); | ||
567 | |||
568 | asd_printk("LSEQ%d MIP 1 >>>>\n", lseq); | ||
569 | PRINT_LMIP_word(asd_ha, lseq, EST_NEXUS_SCBPTR0); | ||
570 | PRINT_LMIP_word(asd_ha, lseq, EST_NEXUS_SCBPTR1); | ||
571 | PRINT_LMIP_word(asd_ha, lseq, EST_NEXUS_SCBPTR2); | ||
572 | PRINT_LMIP_word(asd_ha, lseq, EST_NEXUS_SCBPTR3); | ||
573 | PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_SCB_OPCODE0); | ||
574 | PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_SCB_OPCODE1); | ||
575 | PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_SCB_OPCODE2); | ||
576 | PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_SCB_OPCODE3); | ||
577 | PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_SCB_HEAD); | ||
578 | PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_SCB_TAIL); | ||
579 | PRINT_LMIP_byte(asd_ha, lseq, EST_NEXUS_BUF_AVAIL); | ||
580 | PRINT_LMIP_dword(asd_ha, lseq, TIMEOUT_CONST); | ||
581 | PRINT_LMIP_word(asd_ha, lseq, ISR_SAVE_SINDEX); | ||
582 | PRINT_LMIP_word(asd_ha, lseq, ISR_SAVE_DINDEX); | ||
583 | |||
584 | asd_printk("LSEQ%d MIP 2 >>>>\n", lseq); | ||
585 | PRINT_LMIP_word(asd_ha, lseq, EMPTY_SCB_PTR0); | ||
586 | PRINT_LMIP_word(asd_ha, lseq, EMPTY_SCB_PTR1); | ||
587 | PRINT_LMIP_word(asd_ha, lseq, EMPTY_SCB_PTR2); | ||
588 | PRINT_LMIP_word(asd_ha, lseq, EMPTY_SCB_PTR3); | ||
589 | PRINT_LMIP_byte(asd_ha, lseq, EMPTY_SCB_OPCD0); | ||
590 | PRINT_LMIP_byte(asd_ha, lseq, EMPTY_SCB_OPCD1); | ||
591 | PRINT_LMIP_byte(asd_ha, lseq, EMPTY_SCB_OPCD2); | ||
592 | PRINT_LMIP_byte(asd_ha, lseq, EMPTY_SCB_OPCD3); | ||
593 | PRINT_LMIP_byte(asd_ha, lseq, EMPTY_SCB_HEAD); | ||
594 | PRINT_LMIP_byte(asd_ha, lseq, EMPTY_SCB_TAIL); | ||
595 | PRINT_LMIP_byte(asd_ha, lseq, EMPTY_BUFS_AVAIL); | ||
596 | |||
597 | asd_printk("LSEQ%d MIP 3 >>>>\n", lseq); | ||
598 | PRINT_LMIP_dword(asd_ha, lseq, DEV_PRES_TMR_TOUT_CONST); | ||
599 | PRINT_LMIP_dword(asd_ha, lseq, SATA_INTERLOCK_TIMEOUT); | ||
600 | PRINT_LMIP_dword(asd_ha, lseq, SRST_ASSERT_TIMEOUT); | ||
601 | PRINT_LMIP_dword(asd_ha, lseq, RCV_FIS_TIMEOUT); | ||
602 | PRINT_LMIP_dword(asd_ha, lseq, ONE_MILLISEC_TIMEOUT); | ||
603 | PRINT_LMIP_dword(asd_ha, lseq, TEN_MS_COMINIT_TIMEOUT); | ||
604 | PRINT_LMIP_dword(asd_ha, lseq, SMP_RCV_TIMEOUT); | ||
605 | |||
606 | for (mode = 0; mode < 3; mode++) { | ||
607 | asd_printk("LSEQ%d MDP 0 MODE %d >>>>\n", lseq, mode); | ||
608 | moffs = mode * LSEQ_MODE_SCRATCH_SIZE; | ||
609 | |||
610 | asd_printk(STR_16BIT, "RET_ADDR", 0, | ||
611 | asd_read_reg_word(asd_ha, LmSEQ_RET_ADDR(lseq) | ||
612 | + moffs)); | ||
613 | asd_printk(STR_16BIT, "REG0_MODE", 2, | ||
614 | asd_read_reg_word(asd_ha, LmSEQ_REG0_MODE(lseq) | ||
615 | + moffs)); | ||
616 | asd_printk(STR_16BIT, "MODE_FLAGS", 4, | ||
617 | asd_read_reg_word(asd_ha, LmSEQ_MODE_FLAGS(lseq) | ||
618 | + moffs)); | ||
619 | asd_printk(STR_16BIT, "RET_ADDR2", 0x6, | ||
620 | asd_read_reg_word(asd_ha, LmSEQ_RET_ADDR2(lseq) | ||
621 | + moffs)); | ||
622 | asd_printk(STR_16BIT, "RET_ADDR1", 0x8, | ||
623 | asd_read_reg_word(asd_ha, LmSEQ_RET_ADDR1(lseq) | ||
624 | + moffs)); | ||
625 | asd_printk(STR_8BIT, "OPCODE_TO_CSEQ", 0xB, | ||
626 | asd_read_reg_byte(asd_ha, LmSEQ_OPCODE_TO_CSEQ(lseq) | ||
627 | + moffs)); | ||
628 | asd_printk(STR_16BIT, "DATA_TO_CSEQ", 0xC, | ||
629 | asd_read_reg_word(asd_ha, LmSEQ_DATA_TO_CSEQ(lseq) | ||
630 | + moffs)); | ||
631 | } | ||
632 | |||
633 | asd_printk("LSEQ%d MDP 0 MODE 5 >>>>\n", lseq); | ||
634 | moffs = LSEQ_MODE5_PAGE0_OFFSET; | ||
635 | asd_printk(STR_16BIT, "RET_ADDR", 0, | ||
636 | asd_read_reg_word(asd_ha, LmSEQ_RET_ADDR(lseq) + moffs)); | ||
637 | asd_printk(STR_16BIT, "REG0_MODE", 2, | ||
638 | asd_read_reg_word(asd_ha, LmSEQ_REG0_MODE(lseq) + moffs)); | ||
639 | asd_printk(STR_16BIT, "MODE_FLAGS", 4, | ||
640 | asd_read_reg_word(asd_ha, LmSEQ_MODE_FLAGS(lseq) + moffs)); | ||
641 | asd_printk(STR_16BIT, "RET_ADDR2", 0x6, | ||
642 | asd_read_reg_word(asd_ha, LmSEQ_RET_ADDR2(lseq) + moffs)); | ||
643 | asd_printk(STR_16BIT, "RET_ADDR1", 0x8, | ||
644 | asd_read_reg_word(asd_ha, LmSEQ_RET_ADDR1(lseq) + moffs)); | ||
645 | asd_printk(STR_8BIT, "OPCODE_TO_CSEQ", 0xB, | ||
646 | asd_read_reg_byte(asd_ha, LmSEQ_OPCODE_TO_CSEQ(lseq) + moffs)); | ||
647 | asd_printk(STR_16BIT, "DATA_TO_CSEQ", 0xC, | ||
648 | asd_read_reg_word(asd_ha, LmSEQ_DATA_TO_CSEQ(lseq) + moffs)); | ||
649 | |||
650 | asd_printk("LSEQ%d MDP 0 MODE 0 >>>>\n", lseq); | ||
651 | PRINT_LMIP_word(asd_ha, lseq, FIRST_INV_DDB_SITE); | ||
652 | PRINT_LMIP_word(asd_ha, lseq, EMPTY_TRANS_CTX); | ||
653 | PRINT_LMIP_word(asd_ha, lseq, RESP_LEN); | ||
654 | PRINT_LMIP_word(asd_ha, lseq, FIRST_INV_SCB_SITE); | ||
655 | PRINT_LMIP_dword(asd_ha, lseq, INTEN_SAVE); | ||
656 | PRINT_LMIP_byte(asd_ha, lseq, LINK_RST_FRM_LEN); | ||
657 | PRINT_LMIP_byte(asd_ha, lseq, LINK_RST_PROTOCOL); | ||
658 | PRINT_LMIP_byte(asd_ha, lseq, RESP_STATUS); | ||
659 | PRINT_LMIP_byte(asd_ha, lseq, LAST_LOADED_SGE); | ||
660 | PRINT_LMIP_byte(asd_ha, lseq, SAVE_SCBPTR); | ||
661 | |||
662 | asd_printk("LSEQ%d MDP 0 MODE 1 >>>>\n", lseq); | ||
663 | PRINT_LMIP_word(asd_ha, lseq, Q_XMIT_HEAD); | ||
664 | PRINT_LMIP_word(asd_ha, lseq, M1_EMPTY_TRANS_CTX); | ||
665 | PRINT_LMIP_word(asd_ha, lseq, INI_CONN_TAG); | ||
666 | PRINT_LMIP_byte(asd_ha, lseq, FAILED_OPEN_STATUS); | ||
667 | PRINT_LMIP_byte(asd_ha, lseq, XMIT_REQUEST_TYPE); | ||
668 | PRINT_LMIP_byte(asd_ha, lseq, M1_RESP_STATUS); | ||
669 | PRINT_LMIP_byte(asd_ha, lseq, M1_LAST_LOADED_SGE); | ||
670 | PRINT_LMIP_word(asd_ha, lseq, M1_SAVE_SCBPTR); | ||
671 | |||
672 | asd_printk("LSEQ%d MDP 0 MODE 2 >>>>\n", lseq); | ||
673 | PRINT_LMIP_word(asd_ha, lseq, PORT_COUNTER); | ||
674 | PRINT_LMIP_word(asd_ha, lseq, PM_TABLE_PTR); | ||
675 | PRINT_LMIP_word(asd_ha, lseq, SATA_INTERLOCK_TMR_SAVE); | ||
676 | PRINT_LMIP_word(asd_ha, lseq, IP_BITL); | ||
677 | PRINT_LMIP_word(asd_ha, lseq, COPY_SMP_CONN_TAG); | ||
678 | PRINT_LMIP_byte(asd_ha, lseq, P0M2_OFFS1AH); | ||
679 | |||
680 | asd_printk("LSEQ%d MDP 0 MODE 4/5 >>>>\n", lseq); | ||
681 | PRINT_LMIP_byte(asd_ha, lseq, SAVED_OOB_STATUS); | ||
682 | PRINT_LMIP_byte(asd_ha, lseq, SAVED_OOB_MODE); | ||
683 | PRINT_LMIP_word(asd_ha, lseq, Q_LINK_HEAD); | ||
684 | PRINT_LMIP_byte(asd_ha, lseq, LINK_RST_ERR); | ||
685 | PRINT_LMIP_byte(asd_ha, lseq, SAVED_OOB_SIGNALS); | ||
686 | PRINT_LMIP_byte(asd_ha, lseq, SAS_RESET_MODE); | ||
687 | PRINT_LMIP_byte(asd_ha, lseq, LINK_RESET_RETRY_COUNT); | ||
688 | PRINT_LMIP_byte(asd_ha, lseq, NUM_LINK_RESET_RETRIES); | ||
689 | PRINT_LMIP_word(asd_ha, lseq, OOB_INT_ENABLES); | ||
690 | PRINT_LMIP_word(asd_ha, lseq, NOTIFY_TIMER_TIMEOUT); | ||
691 | PRINT_LMIP_word(asd_ha, lseq, NOTIFY_TIMER_DOWN_COUNT); | ||
692 | |||
693 | asd_printk("LSEQ%d MDP 1 MODE 0 >>>>\n", lseq); | ||
694 | PRINT_LMIP_qword(asd_ha, lseq, SG_LIST_PTR_ADDR0); | ||
695 | PRINT_LMIP_qword(asd_ha, lseq, SG_LIST_PTR_ADDR1); | ||
696 | |||
697 | asd_printk("LSEQ%d MDP 1 MODE 1 >>>>\n", lseq); | ||
698 | PRINT_LMIP_qword(asd_ha, lseq, M1_SG_LIST_PTR_ADDR0); | ||
699 | PRINT_LMIP_qword(asd_ha, lseq, M1_SG_LIST_PTR_ADDR1); | ||
700 | |||
701 | asd_printk("LSEQ%d MDP 1 MODE 2 >>>>\n", lseq); | ||
702 | PRINT_LMIP_dword(asd_ha, lseq, INVALID_DWORD_COUNT); | ||
703 | PRINT_LMIP_dword(asd_ha, lseq, DISPARITY_ERROR_COUNT); | ||
704 | PRINT_LMIP_dword(asd_ha, lseq, LOSS_OF_SYNC_COUNT); | ||
705 | |||
706 | asd_printk("LSEQ%d MDP 1 MODE 4/5 >>>>\n", lseq); | ||
707 | PRINT_LMIP_dword(asd_ha, lseq, FRAME_TYPE_MASK); | ||
708 | PRINT_LMIP_dword(asd_ha, lseq, HASHED_SRC_ADDR_MASK_PRINT); | ||
709 | PRINT_LMIP_byte(asd_ha, lseq, NUM_FILL_BYTES_MASK); | ||
710 | PRINT_LMIP_word(asd_ha, lseq, TAG_MASK); | ||
711 | PRINT_LMIP_word(asd_ha, lseq, TARGET_PORT_XFER_TAG); | ||
712 | PRINT_LMIP_dword(asd_ha, lseq, DATA_OFFSET); | ||
713 | |||
714 | asd_printk("LSEQ%d MDP 2 MODE 0 >>>>\n", lseq); | ||
715 | PRINT_LMIP_dword(asd_ha, lseq, SMP_RCV_TIMER_TERM_TS); | ||
716 | PRINT_LMIP_byte(asd_ha, lseq, DEVICE_BITS); | ||
717 | PRINT_LMIP_word(asd_ha, lseq, SDB_DDB); | ||
718 | PRINT_LMIP_word(asd_ha, lseq, SDB_NUM_TAGS); | ||
719 | PRINT_LMIP_word(asd_ha, lseq, SDB_CURR_TAG); | ||
720 | |||
721 | asd_printk("LSEQ%d MDP 2 MODE 1 >>>>\n", lseq); | ||
722 | PRINT_LMIP_qword(asd_ha, lseq, TX_ID_ADDR_FRAME); | ||
723 | PRINT_LMIP_dword(asd_ha, lseq, OPEN_TIMER_TERM_TS); | ||
724 | PRINT_LMIP_dword(asd_ha, lseq, SRST_AS_TIMER_TERM_TS); | ||
725 | PRINT_LMIP_dword(asd_ha, lseq, LAST_LOADED_SG_EL); | ||
726 | |||
727 | asd_printk("LSEQ%d MDP 2 MODE 2 >>>>\n", lseq); | ||
728 | PRINT_LMIP_dword(asd_ha, lseq, CLOSE_TIMER_TERM_TS); | ||
729 | PRINT_LMIP_dword(asd_ha, lseq, BREAK_TIMER_TERM_TS); | ||
730 | PRINT_LMIP_dword(asd_ha, lseq, DWS_RESET_TIMER_TERM_TS); | ||
731 | PRINT_LMIP_dword(asd_ha, lseq, SATA_INTERLOCK_TIMER_TERM_TS); | ||
732 | PRINT_LMIP_dword(asd_ha, lseq, MCTL_TIMER_TERM_TS); | ||
733 | |||
734 | asd_printk("LSEQ%d MDP 2 MODE 4/5 >>>>\n", lseq); | ||
735 | PRINT_LMIP_dword(asd_ha, lseq, COMINIT_TIMER_TERM_TS); | ||
736 | PRINT_LMIP_dword(asd_ha, lseq, RCV_ID_TIMER_TERM_TS); | ||
737 | PRINT_LMIP_dword(asd_ha, lseq, RCV_FIS_TIMER_TERM_TS); | ||
738 | PRINT_LMIP_dword(asd_ha, lseq, DEV_PRES_TIMER_TERM_TS); | ||
739 | } | ||
740 | |||
741 | /** | ||
742 | * asd_dump_ddb_site -- dump a CSEQ DDB site | ||
743 | * @asd_ha: pointer to host adapter structure | ||
744 | * @site_no: site number of interest | ||
745 | */ | ||
746 | void asd_dump_target_ddb(struct asd_ha_struct *asd_ha, u16 site_no) | ||
747 | { | ||
748 | if (site_no >= asd_ha->hw_prof.max_ddbs) | ||
749 | return; | ||
750 | |||
751 | #define DDB_FIELDB(__name) \ | ||
752 | asd_ddbsite_read_byte(asd_ha, site_no, \ | ||
753 | offsetof(struct asd_ddb_ssp_smp_target_port, __name)) | ||
754 | #define DDB2_FIELDB(__name) \ | ||
755 | asd_ddbsite_read_byte(asd_ha, site_no, \ | ||
756 | offsetof(struct asd_ddb_stp_sata_target_port, __name)) | ||
757 | #define DDB_FIELDW(__name) \ | ||
758 | asd_ddbsite_read_word(asd_ha, site_no, \ | ||
759 | offsetof(struct asd_ddb_ssp_smp_target_port, __name)) | ||
760 | |||
761 | #define DDB_FIELDD(__name) \ | ||
762 | asd_ddbsite_read_dword(asd_ha, site_no, \ | ||
763 | offsetof(struct asd_ddb_ssp_smp_target_port, __name)) | ||
764 | |||
765 | asd_printk("DDB: 0x%02x\n", site_no); | ||
766 | asd_printk("conn_type: 0x%02x\n", DDB_FIELDB(conn_type)); | ||
767 | asd_printk("conn_rate: 0x%02x\n", DDB_FIELDB(conn_rate)); | ||
768 | asd_printk("init_conn_tag: 0x%04x\n", be16_to_cpu(DDB_FIELDW(init_conn_tag))); | ||
769 | asd_printk("send_queue_head: 0x%04x\n", be16_to_cpu(DDB_FIELDW(send_queue_head))); | ||
770 | asd_printk("sq_suspended: 0x%02x\n", DDB_FIELDB(sq_suspended)); | ||
771 | asd_printk("DDB Type: 0x%02x\n", DDB_FIELDB(ddb_type)); | ||
772 | asd_printk("AWT Default: 0x%04x\n", DDB_FIELDW(awt_def)); | ||
773 | asd_printk("compat_features: 0x%02x\n", DDB_FIELDB(compat_features)); | ||
774 | asd_printk("Pathway Blocked Count: 0x%02x\n", | ||
775 | DDB_FIELDB(pathway_blocked_count)); | ||
776 | asd_printk("arb_wait_time: 0x%04x\n", DDB_FIELDW(arb_wait_time)); | ||
777 | asd_printk("more_compat_features: 0x%08x\n", | ||
778 | DDB_FIELDD(more_compat_features)); | ||
779 | asd_printk("Conn Mask: 0x%02x\n", DDB_FIELDB(conn_mask)); | ||
780 | asd_printk("flags: 0x%02x\n", DDB_FIELDB(flags)); | ||
781 | asd_printk("flags2: 0x%02x\n", DDB2_FIELDB(flags2)); | ||
782 | asd_printk("ExecQ Tail: 0x%04x\n",DDB_FIELDW(exec_queue_tail)); | ||
783 | asd_printk("SendQ Tail: 0x%04x\n",DDB_FIELDW(send_queue_tail)); | ||
784 | asd_printk("Active Task Count: 0x%04x\n", | ||
785 | DDB_FIELDW(active_task_count)); | ||
786 | asd_printk("ITNL Reason: 0x%02x\n", DDB_FIELDB(itnl_reason)); | ||
787 | asd_printk("ITNL Timeout Const: 0x%04x\n", DDB_FIELDW(itnl_timeout)); | ||
788 | asd_printk("ITNL timestamp: 0x%08x\n", DDB_FIELDD(itnl_timestamp)); | ||
789 | } | ||
790 | |||
791 | void asd_dump_ddb_0(struct asd_ha_struct *asd_ha) | ||
792 | { | ||
793 | #define DDB0_FIELDB(__name) \ | ||
794 | asd_ddbsite_read_byte(asd_ha, 0, \ | ||
795 | offsetof(struct asd_ddb_seq_shared, __name)) | ||
796 | #define DDB0_FIELDW(__name) \ | ||
797 | asd_ddbsite_read_word(asd_ha, 0, \ | ||
798 | offsetof(struct asd_ddb_seq_shared, __name)) | ||
799 | |||
800 | #define DDB0_FIELDD(__name) \ | ||
801 | asd_ddbsite_read_dword(asd_ha,0 , \ | ||
802 | offsetof(struct asd_ddb_seq_shared, __name)) | ||
803 | |||
804 | #define DDB0_FIELDA(__name, _o) \ | ||
805 | asd_ddbsite_read_byte(asd_ha, 0, \ | ||
806 | offsetof(struct asd_ddb_seq_shared, __name)+_o) | ||
807 | |||
808 | |||
809 | asd_printk("DDB: 0\n"); | ||
810 | asd_printk("q_free_ddb_head:%04x\n", DDB0_FIELDW(q_free_ddb_head)); | ||
811 | asd_printk("q_free_ddb_tail:%04x\n", DDB0_FIELDW(q_free_ddb_tail)); | ||
812 | asd_printk("q_free_ddb_cnt:%04x\n", DDB0_FIELDW(q_free_ddb_cnt)); | ||
813 | asd_printk("q_used_ddb_head:%04x\n", DDB0_FIELDW(q_used_ddb_head)); | ||
814 | asd_printk("q_used_ddb_tail:%04x\n", DDB0_FIELDW(q_used_ddb_tail)); | ||
815 | asd_printk("shared_mem_lock:%04x\n", DDB0_FIELDW(shared_mem_lock)); | ||
816 | asd_printk("smp_conn_tag:%04x\n", DDB0_FIELDW(smp_conn_tag)); | ||
817 | asd_printk("est_nexus_buf_cnt:%04x\n", DDB0_FIELDW(est_nexus_buf_cnt)); | ||
818 | asd_printk("est_nexus_buf_thresh:%04x\n", | ||
819 | DDB0_FIELDW(est_nexus_buf_thresh)); | ||
820 | asd_printk("conn_not_active:%02x\n", DDB0_FIELDB(conn_not_active)); | ||
821 | asd_printk("phy_is_up:%02x\n", DDB0_FIELDB(phy_is_up)); | ||
822 | asd_printk("port_map_by_links:%02x %02x %02x %02x " | ||
823 | "%02x %02x %02x %02x\n", | ||
824 | DDB0_FIELDA(port_map_by_links, 0), | ||
825 | DDB0_FIELDA(port_map_by_links, 1), | ||
826 | DDB0_FIELDA(port_map_by_links, 2), | ||
827 | DDB0_FIELDA(port_map_by_links, 3), | ||
828 | DDB0_FIELDA(port_map_by_links, 4), | ||
829 | DDB0_FIELDA(port_map_by_links, 5), | ||
830 | DDB0_FIELDA(port_map_by_links, 6), | ||
831 | DDB0_FIELDA(port_map_by_links, 7)); | ||
832 | } | ||
833 | |||
834 | static void asd_dump_scb_site(struct asd_ha_struct *asd_ha, u16 site_no) | ||
835 | { | ||
836 | |||
837 | #define SCB_FIELDB(__name) \ | ||
838 | asd_scbsite_read_byte(asd_ha, site_no, sizeof(struct scb_header) \ | ||
839 | + offsetof(struct initiate_ssp_task, __name)) | ||
840 | #define SCB_FIELDW(__name) \ | ||
841 | asd_scbsite_read_word(asd_ha, site_no, sizeof(struct scb_header) \ | ||
842 | + offsetof(struct initiate_ssp_task, __name)) | ||
843 | #define SCB_FIELDD(__name) \ | ||
844 | asd_scbsite_read_dword(asd_ha, site_no, sizeof(struct scb_header) \ | ||
845 | + offsetof(struct initiate_ssp_task, __name)) | ||
846 | |||
847 | asd_printk("Total Xfer Len: 0x%08x.\n", SCB_FIELDD(total_xfer_len)); | ||
848 | asd_printk("Frame Type: 0x%02x.\n", SCB_FIELDB(ssp_frame.frame_type)); | ||
849 | asd_printk("Tag: 0x%04x.\n", SCB_FIELDW(ssp_frame.tag)); | ||
850 | asd_printk("Target Port Xfer Tag: 0x%04x.\n", | ||
851 | SCB_FIELDW(ssp_frame.tptt)); | ||
852 | asd_printk("Data Offset: 0x%08x.\n", SCB_FIELDW(ssp_frame.data_offs)); | ||
853 | asd_printk("Retry Count: 0x%02x.\n", SCB_FIELDB(retry_count)); | ||
854 | } | ||
855 | |||
856 | /** | ||
857 | * asd_dump_scb_sites -- dump currently used CSEQ SCB sites | ||
858 | * @asd_ha: pointer to host adapter struct | ||
859 | */ | ||
860 | void asd_dump_scb_sites(struct asd_ha_struct *asd_ha) | ||
861 | { | ||
862 | u16 site_no; | ||
863 | |||
864 | for (site_no = 0; site_no < asd_ha->hw_prof.max_scbs; site_no++) { | ||
865 | u8 opcode; | ||
866 | |||
867 | if (!SCB_SITE_VALID(site_no)) | ||
868 | continue; | ||
869 | |||
870 | /* We are only interested in SCB sites currently used. | ||
871 | */ | ||
872 | opcode = asd_scbsite_read_byte(asd_ha, site_no, | ||
873 | offsetof(struct scb_header, | ||
874 | opcode)); | ||
875 | if (opcode == 0xFF) | ||
876 | continue; | ||
877 | |||
878 | asd_printk("\nSCB: 0x%x\n", site_no); | ||
879 | asd_dump_scb_site(asd_ha, site_no); | ||
880 | } | ||
881 | } | ||
882 | |||
883 | /** | ||
884 | * ads_dump_seq_state -- dump CSEQ and LSEQ states | ||
885 | * @asd_ha: pointer to host adapter structure | ||
886 | * @lseq_mask: mask of LSEQs of interest | ||
887 | */ | ||
888 | void asd_dump_seq_state(struct asd_ha_struct *asd_ha, u8 lseq_mask) | ||
889 | { | ||
890 | int lseq; | ||
891 | |||
892 | asd_dump_cseq_state(asd_ha); | ||
893 | |||
894 | if (lseq_mask != 0) | ||
895 | for_each_sequencer(lseq_mask, lseq_mask, lseq) | ||
896 | asd_dump_lseq_state(asd_ha, lseq); | ||
897 | } | ||
898 | |||
899 | void asd_dump_frame_rcvd(struct asd_phy *phy, | ||
900 | struct done_list_struct *dl) | ||
901 | { | ||
902 | unsigned long flags; | ||
903 | int i; | ||
904 | |||
905 | switch ((dl->status_block[1] & 0x70) >> 3) { | ||
906 | case SAS_PROTO_STP: | ||
907 | ASD_DPRINTK("STP proto device-to-host FIS:\n"); | ||
908 | break; | ||
909 | default: | ||
910 | case SAS_PROTO_SSP: | ||
911 | ASD_DPRINTK("SAS proto IDENTIFY:\n"); | ||
912 | break; | ||
913 | } | ||
914 | spin_lock_irqsave(&phy->sas_phy.frame_rcvd_lock, flags); | ||
915 | for (i = 0; i < phy->sas_phy.frame_rcvd_size; i+=4) | ||
916 | ASD_DPRINTK("%02x: %02x %02x %02x %02x\n", | ||
917 | i, | ||
918 | phy->frame_rcvd[i], | ||
919 | phy->frame_rcvd[i+1], | ||
920 | phy->frame_rcvd[i+2], | ||
921 | phy->frame_rcvd[i+3]); | ||
922 | spin_unlock_irqrestore(&phy->sas_phy.frame_rcvd_lock, flags); | ||
923 | } | ||
924 | |||
925 | static inline void asd_dump_scb(struct asd_ascb *ascb, int ind) | ||
926 | { | ||
927 | asd_printk("scb%d: vaddr: 0x%p, dma_handle: 0x%llx, next: 0x%llx, " | ||
928 | "index:%d, opcode:0x%02x\n", | ||
929 | ind, ascb->dma_scb.vaddr, | ||
930 | (unsigned long long)ascb->dma_scb.dma_handle, | ||
931 | (unsigned long long) | ||
932 | le64_to_cpu(ascb->scb->header.next_scb), | ||
933 | le16_to_cpu(ascb->scb->header.index), | ||
934 | ascb->scb->header.opcode); | ||
935 | } | ||
936 | |||
937 | void asd_dump_scb_list(struct asd_ascb *ascb, int num) | ||
938 | { | ||
939 | int i = 0; | ||
940 | |||
941 | asd_printk("dumping %d scbs:\n", num); | ||
942 | |||
943 | asd_dump_scb(ascb, i++); | ||
944 | --num; | ||
945 | |||
946 | if (num > 0 && !list_empty(&ascb->list)) { | ||
947 | struct list_head *el; | ||
948 | |||
949 | list_for_each(el, &ascb->list) { | ||
950 | struct asd_ascb *s = list_entry(el, struct asd_ascb, | ||
951 | list); | ||
952 | asd_dump_scb(s, i++); | ||
953 | if (--num <= 0) | ||
954 | break; | ||
955 | } | ||
956 | } | ||
957 | } | ||
958 | |||
959 | #endif /* ASD_DEBUG */ | ||
diff --git a/drivers/scsi/aic94xx/aic94xx_dump.h b/drivers/scsi/aic94xx/aic94xx_dump.h new file mode 100644 index 000000000000..0c388e7da6bb --- /dev/null +++ b/drivers/scsi/aic94xx/aic94xx_dump.h | |||
@@ -0,0 +1,52 @@ | |||
1 | /* | ||
2 | * Aic94xx SAS/SATA driver dump header file. | ||
3 | * | ||
4 | * Copyright (C) 2005 Adaptec, Inc. All rights reserved. | ||
5 | * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> | ||
6 | * | ||
7 | * This file is licensed under GPLv2. | ||
8 | * | ||
9 | * This file is part of the aic94xx driver. | ||
10 | * | ||
11 | * The aic94xx driver is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License as | ||
13 | * published by the Free Software Foundation; version 2 of the | ||
14 | * License. | ||
15 | * | ||
16 | * The aic94xx driver is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
19 | * General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with the aic94xx driver; if not, write to the Free Software | ||
23 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #ifndef _AIC94XX_DUMP_H_ | ||
28 | #define _AIC94XX_DUMP_H_ | ||
29 | |||
30 | #ifdef ASD_DEBUG | ||
31 | |||
32 | void asd_dump_ddb_0(struct asd_ha_struct *asd_ha); | ||
33 | void asd_dump_target_ddb(struct asd_ha_struct *asd_ha, u16 site_no); | ||
34 | void asd_dump_scb_sites(struct asd_ha_struct *asd_ha); | ||
35 | void asd_dump_seq_state(struct asd_ha_struct *asd_ha, u8 lseq_mask); | ||
36 | void asd_dump_frame_rcvd(struct asd_phy *phy, | ||
37 | struct done_list_struct *dl); | ||
38 | void asd_dump_scb_list(struct asd_ascb *ascb, int num); | ||
39 | #else /* ASD_DEBUG */ | ||
40 | |||
41 | static inline void asd_dump_ddb_0(struct asd_ha_struct *asd_ha) { } | ||
42 | static inline void asd_dump_target_ddb(struct asd_ha_struct *asd_ha, | ||
43 | u16 site_no) { } | ||
44 | static inline void asd_dump_scb_sites(struct asd_ha_struct *asd_ha) { } | ||
45 | static inline void asd_dump_seq_state(struct asd_ha_struct *asd_ha, | ||
46 | u8 lseq_mask) { } | ||
47 | static inline void asd_dump_frame_rcvd(struct asd_phy *phy, | ||
48 | struct done_list_struct *dl) { } | ||
49 | static inline void asd_dump_scb_list(struct asd_ascb *ascb, int num) { } | ||
50 | #endif /* ASD_DEBUG */ | ||
51 | |||
52 | #endif /* _AIC94XX_DUMP_H_ */ | ||
diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.c b/drivers/scsi/aic94xx/aic94xx_hwi.c new file mode 100644 index 000000000000..075cea85b56b --- /dev/null +++ b/drivers/scsi/aic94xx/aic94xx_hwi.c | |||
@@ -0,0 +1,1376 @@ | |||
1 | /* | ||
2 | * Aic94xx SAS/SATA driver hardware interface. | ||
3 | * | ||
4 | * Copyright (C) 2005 Adaptec, Inc. All rights reserved. | ||
5 | * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> | ||
6 | * | ||
7 | * This file is licensed under GPLv2. | ||
8 | * | ||
9 | * This file is part of the aic94xx driver. | ||
10 | * | ||
11 | * The aic94xx driver is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License as | ||
13 | * published by the Free Software Foundation; version 2 of the | ||
14 | * License. | ||
15 | * | ||
16 | * The aic94xx driver is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
19 | * General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with the aic94xx driver; if not, write to the Free Software | ||
23 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #include <linux/pci.h> | ||
28 | #include <linux/delay.h> | ||
29 | #include <linux/module.h> | ||
30 | |||
31 | #include "aic94xx.h" | ||
32 | #include "aic94xx_reg.h" | ||
33 | #include "aic94xx_hwi.h" | ||
34 | #include "aic94xx_seq.h" | ||
35 | #include "aic94xx_dump.h" | ||
36 | |||
37 | u32 MBAR0_SWB_SIZE; | ||
38 | |||
39 | /* ---------- Initialization ---------- */ | ||
40 | |||
41 | static void asd_get_user_sas_addr(struct asd_ha_struct *asd_ha) | ||
42 | { | ||
43 | extern char sas_addr_str[]; | ||
44 | /* If the user has specified a WWN it overrides other settings | ||
45 | */ | ||
46 | if (sas_addr_str[0] != '\0') | ||
47 | asd_destringify_sas_addr(asd_ha->hw_prof.sas_addr, | ||
48 | sas_addr_str); | ||
49 | else if (asd_ha->hw_prof.sas_addr[0] != 0) | ||
50 | asd_stringify_sas_addr(sas_addr_str, asd_ha->hw_prof.sas_addr); | ||
51 | } | ||
52 | |||
53 | static void asd_propagate_sas_addr(struct asd_ha_struct *asd_ha) | ||
54 | { | ||
55 | int i; | ||
56 | |||
57 | for (i = 0; i < ASD_MAX_PHYS; i++) { | ||
58 | if (asd_ha->hw_prof.phy_desc[i].sas_addr[0] == 0) | ||
59 | continue; | ||
60 | /* Set a phy's address only if it has none. | ||
61 | */ | ||
62 | ASD_DPRINTK("setting phy%d addr to %llx\n", i, | ||
63 | SAS_ADDR(asd_ha->hw_prof.sas_addr)); | ||
64 | memcpy(asd_ha->hw_prof.phy_desc[i].sas_addr, | ||
65 | asd_ha->hw_prof.sas_addr, SAS_ADDR_SIZE); | ||
66 | } | ||
67 | } | ||
68 | |||
69 | /* ---------- PHY initialization ---------- */ | ||
70 | |||
71 | static void asd_init_phy_identify(struct asd_phy *phy) | ||
72 | { | ||
73 | phy->identify_frame = phy->id_frm_tok->vaddr; | ||
74 | |||
75 | memset(phy->identify_frame, 0, sizeof(*phy->identify_frame)); | ||
76 | |||
77 | phy->identify_frame->dev_type = SAS_END_DEV; | ||
78 | if (phy->sas_phy.role & PHY_ROLE_INITIATOR) | ||
79 | phy->identify_frame->initiator_bits = phy->sas_phy.iproto; | ||
80 | if (phy->sas_phy.role & PHY_ROLE_TARGET) | ||
81 | phy->identify_frame->target_bits = phy->sas_phy.tproto; | ||
82 | memcpy(phy->identify_frame->sas_addr, phy->phy_desc->sas_addr, | ||
83 | SAS_ADDR_SIZE); | ||
84 | phy->identify_frame->phy_id = phy->sas_phy.id; | ||
85 | } | ||
86 | |||
87 | static int asd_init_phy(struct asd_phy *phy) | ||
88 | { | ||
89 | struct asd_ha_struct *asd_ha = phy->sas_phy.ha->lldd_ha; | ||
90 | struct asd_sas_phy *sas_phy = &phy->sas_phy; | ||
91 | |||
92 | sas_phy->enabled = 1; | ||
93 | sas_phy->class = SAS; | ||
94 | sas_phy->iproto = SAS_PROTO_ALL; | ||
95 | sas_phy->tproto = 0; | ||
96 | sas_phy->type = PHY_TYPE_PHYSICAL; | ||
97 | sas_phy->role = PHY_ROLE_INITIATOR; | ||
98 | sas_phy->oob_mode = OOB_NOT_CONNECTED; | ||
99 | sas_phy->linkrate = PHY_LINKRATE_NONE; | ||
100 | |||
101 | phy->id_frm_tok = asd_alloc_coherent(asd_ha, | ||
102 | sizeof(*phy->identify_frame), | ||
103 | GFP_KERNEL); | ||
104 | if (!phy->id_frm_tok) { | ||
105 | asd_printk("no mem for IDENTIFY for phy%d\n", sas_phy->id); | ||
106 | return -ENOMEM; | ||
107 | } else | ||
108 | asd_init_phy_identify(phy); | ||
109 | |||
110 | memset(phy->frame_rcvd, 0, sizeof(phy->frame_rcvd)); | ||
111 | |||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | static int asd_init_phys(struct asd_ha_struct *asd_ha) | ||
116 | { | ||
117 | u8 i; | ||
118 | u8 phy_mask = asd_ha->hw_prof.enabled_phys; | ||
119 | |||
120 | for (i = 0; i < ASD_MAX_PHYS; i++) { | ||
121 | struct asd_phy *phy = &asd_ha->phys[i]; | ||
122 | |||
123 | phy->phy_desc = &asd_ha->hw_prof.phy_desc[i]; | ||
124 | |||
125 | phy->sas_phy.enabled = 0; | ||
126 | phy->sas_phy.id = i; | ||
127 | phy->sas_phy.sas_addr = &phy->phy_desc->sas_addr[0]; | ||
128 | phy->sas_phy.frame_rcvd = &phy->frame_rcvd[0]; | ||
129 | phy->sas_phy.ha = &asd_ha->sas_ha; | ||
130 | phy->sas_phy.lldd_phy = phy; | ||
131 | } | ||
132 | |||
133 | /* Now enable and initialize only the enabled phys. */ | ||
134 | for_each_phy(phy_mask, phy_mask, i) { | ||
135 | int err = asd_init_phy(&asd_ha->phys[i]); | ||
136 | if (err) | ||
137 | return err; | ||
138 | } | ||
139 | |||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | /* ---------- Sliding windows ---------- */ | ||
144 | |||
145 | static int asd_init_sw(struct asd_ha_struct *asd_ha) | ||
146 | { | ||
147 | struct pci_dev *pcidev = asd_ha->pcidev; | ||
148 | int err; | ||
149 | u32 v; | ||
150 | |||
151 | /* Unlock MBARs */ | ||
152 | err = pci_read_config_dword(pcidev, PCI_CONF_MBAR_KEY, &v); | ||
153 | if (err) { | ||
154 | asd_printk("couldn't access conf. space of %s\n", | ||
155 | pci_name(pcidev)); | ||
156 | goto Err; | ||
157 | } | ||
158 | if (v) | ||
159 | err = pci_write_config_dword(pcidev, PCI_CONF_MBAR_KEY, v); | ||
160 | if (err) { | ||
161 | asd_printk("couldn't write to MBAR_KEY of %s\n", | ||
162 | pci_name(pcidev)); | ||
163 | goto Err; | ||
164 | } | ||
165 | |||
166 | /* Set sliding windows A, B and C to point to proper internal | ||
167 | * memory regions. | ||
168 | */ | ||
169 | pci_write_config_dword(pcidev, PCI_CONF_MBAR0_SWA, REG_BASE_ADDR); | ||
170 | pci_write_config_dword(pcidev, PCI_CONF_MBAR0_SWB, | ||
171 | REG_BASE_ADDR_CSEQCIO); | ||
172 | pci_write_config_dword(pcidev, PCI_CONF_MBAR0_SWC, REG_BASE_ADDR_EXSI); | ||
173 | asd_ha->io_handle[0].swa_base = REG_BASE_ADDR; | ||
174 | asd_ha->io_handle[0].swb_base = REG_BASE_ADDR_CSEQCIO; | ||
175 | asd_ha->io_handle[0].swc_base = REG_BASE_ADDR_EXSI; | ||
176 | MBAR0_SWB_SIZE = asd_ha->io_handle[0].len - 0x80; | ||
177 | if (!asd_ha->iospace) { | ||
178 | /* MBAR1 will point to OCM (On Chip Memory) */ | ||
179 | pci_write_config_dword(pcidev, PCI_CONF_MBAR1, OCM_BASE_ADDR); | ||
180 | asd_ha->io_handle[1].swa_base = OCM_BASE_ADDR; | ||
181 | } | ||
182 | spin_lock_init(&asd_ha->iolock); | ||
183 | Err: | ||
184 | return err; | ||
185 | } | ||
186 | |||
187 | /* ---------- SCB initialization ---------- */ | ||
188 | |||
189 | /** | ||
190 | * asd_init_scbs - manually allocate the first SCB. | ||
191 | * @asd_ha: pointer to host adapter structure | ||
192 | * | ||
193 | * This allocates the very first SCB which would be sent to the | ||
194 | * sequencer for execution. Its bus address is written to | ||
195 | * CSEQ_Q_NEW_POINTER, mode page 2, mode 8. Since the bus address of | ||
196 | * the _next_ scb to be DMA-ed to the host adapter is read from the last | ||
197 | * SCB DMA-ed to the host adapter, we have to always stay one step | ||
198 | * ahead of the sequencer and keep one SCB already allocated. | ||
199 | */ | ||
200 | static int asd_init_scbs(struct asd_ha_struct *asd_ha) | ||
201 | { | ||
202 | struct asd_seq_data *seq = &asd_ha->seq; | ||
203 | int bitmap_bytes; | ||
204 | |||
205 | /* allocate the index array and bitmap */ | ||
206 | asd_ha->seq.tc_index_bitmap_bits = asd_ha->hw_prof.max_scbs; | ||
207 | asd_ha->seq.tc_index_array = kzalloc(asd_ha->seq.tc_index_bitmap_bits* | ||
208 | sizeof(void *), GFP_KERNEL); | ||
209 | if (!asd_ha->seq.tc_index_array) | ||
210 | return -ENOMEM; | ||
211 | |||
212 | bitmap_bytes = (asd_ha->seq.tc_index_bitmap_bits+7)/8; | ||
213 | bitmap_bytes = BITS_TO_LONGS(bitmap_bytes*8)*sizeof(unsigned long); | ||
214 | asd_ha->seq.tc_index_bitmap = kzalloc(bitmap_bytes, GFP_KERNEL); | ||
215 | if (!asd_ha->seq.tc_index_bitmap) | ||
216 | return -ENOMEM; | ||
217 | |||
218 | spin_lock_init(&seq->tc_index_lock); | ||
219 | |||
220 | seq->next_scb.size = sizeof(struct scb); | ||
221 | seq->next_scb.vaddr = dma_pool_alloc(asd_ha->scb_pool, GFP_KERNEL, | ||
222 | &seq->next_scb.dma_handle); | ||
223 | if (!seq->next_scb.vaddr) { | ||
224 | kfree(asd_ha->seq.tc_index_bitmap); | ||
225 | kfree(asd_ha->seq.tc_index_array); | ||
226 | asd_ha->seq.tc_index_bitmap = NULL; | ||
227 | asd_ha->seq.tc_index_array = NULL; | ||
228 | return -ENOMEM; | ||
229 | } | ||
230 | |||
231 | seq->pending = 0; | ||
232 | spin_lock_init(&seq->pend_q_lock); | ||
233 | INIT_LIST_HEAD(&seq->pend_q); | ||
234 | |||
235 | return 0; | ||
236 | } | ||
237 | |||
238 | static inline void asd_get_max_scb_ddb(struct asd_ha_struct *asd_ha) | ||
239 | { | ||
240 | asd_ha->hw_prof.max_scbs = asd_get_cmdctx_size(asd_ha)/ASD_SCB_SIZE; | ||
241 | asd_ha->hw_prof.max_ddbs = asd_get_devctx_size(asd_ha)/ASD_DDB_SIZE; | ||
242 | ASD_DPRINTK("max_scbs:%d, max_ddbs:%d\n", | ||
243 | asd_ha->hw_prof.max_scbs, | ||
244 | asd_ha->hw_prof.max_ddbs); | ||
245 | } | ||
246 | |||
247 | /* ---------- Done List initialization ---------- */ | ||
248 | |||
249 | static void asd_dl_tasklet_handler(unsigned long); | ||
250 | |||
251 | static int asd_init_dl(struct asd_ha_struct *asd_ha) | ||
252 | { | ||
253 | asd_ha->seq.actual_dl | ||
254 | = asd_alloc_coherent(asd_ha, | ||
255 | ASD_DL_SIZE * sizeof(struct done_list_struct), | ||
256 | GFP_KERNEL); | ||
257 | if (!asd_ha->seq.actual_dl) | ||
258 | return -ENOMEM; | ||
259 | asd_ha->seq.dl = asd_ha->seq.actual_dl->vaddr; | ||
260 | asd_ha->seq.dl_toggle = ASD_DEF_DL_TOGGLE; | ||
261 | asd_ha->seq.dl_next = 0; | ||
262 | tasklet_init(&asd_ha->seq.dl_tasklet, asd_dl_tasklet_handler, | ||
263 | (unsigned long) asd_ha); | ||
264 | |||
265 | return 0; | ||
266 | } | ||
267 | |||
268 | /* ---------- EDB and ESCB init ---------- */ | ||
269 | |||
270 | static int asd_alloc_edbs(struct asd_ha_struct *asd_ha, unsigned int gfp_flags) | ||
271 | { | ||
272 | struct asd_seq_data *seq = &asd_ha->seq; | ||
273 | int i; | ||
274 | |||
275 | seq->edb_arr = kmalloc(seq->num_edbs*sizeof(*seq->edb_arr), gfp_flags); | ||
276 | if (!seq->edb_arr) | ||
277 | return -ENOMEM; | ||
278 | |||
279 | for (i = 0; i < seq->num_edbs; i++) { | ||
280 | seq->edb_arr[i] = asd_alloc_coherent(asd_ha, ASD_EDB_SIZE, | ||
281 | gfp_flags); | ||
282 | if (!seq->edb_arr[i]) | ||
283 | goto Err_unroll; | ||
284 | memset(seq->edb_arr[i]->vaddr, 0, ASD_EDB_SIZE); | ||
285 | } | ||
286 | |||
287 | ASD_DPRINTK("num_edbs:%d\n", seq->num_edbs); | ||
288 | |||
289 | return 0; | ||
290 | |||
291 | Err_unroll: | ||
292 | for (i-- ; i >= 0; i--) | ||
293 | asd_free_coherent(asd_ha, seq->edb_arr[i]); | ||
294 | kfree(seq->edb_arr); | ||
295 | seq->edb_arr = NULL; | ||
296 | |||
297 | return -ENOMEM; | ||
298 | } | ||
299 | |||
300 | static int asd_alloc_escbs(struct asd_ha_struct *asd_ha, | ||
301 | unsigned int gfp_flags) | ||
302 | { | ||
303 | struct asd_seq_data *seq = &asd_ha->seq; | ||
304 | struct asd_ascb *escb; | ||
305 | int i, escbs; | ||
306 | |||
307 | seq->escb_arr = kmalloc(seq->num_escbs*sizeof(*seq->escb_arr), | ||
308 | gfp_flags); | ||
309 | if (!seq->escb_arr) | ||
310 | return -ENOMEM; | ||
311 | |||
312 | escbs = seq->num_escbs; | ||
313 | escb = asd_ascb_alloc_list(asd_ha, &escbs, gfp_flags); | ||
314 | if (!escb) { | ||
315 | asd_printk("couldn't allocate list of escbs\n"); | ||
316 | goto Err; | ||
317 | } | ||
318 | seq->num_escbs -= escbs; /* subtract what was not allocated */ | ||
319 | ASD_DPRINTK("num_escbs:%d\n", seq->num_escbs); | ||
320 | |||
321 | for (i = 0; i < seq->num_escbs; i++, escb = list_entry(escb->list.next, | ||
322 | struct asd_ascb, | ||
323 | list)) { | ||
324 | seq->escb_arr[i] = escb; | ||
325 | escb->scb->header.opcode = EMPTY_SCB; | ||
326 | } | ||
327 | |||
328 | return 0; | ||
329 | Err: | ||
330 | kfree(seq->escb_arr); | ||
331 | seq->escb_arr = NULL; | ||
332 | return -ENOMEM; | ||
333 | |||
334 | } | ||
335 | |||
336 | static void asd_assign_edbs2escbs(struct asd_ha_struct *asd_ha) | ||
337 | { | ||
338 | struct asd_seq_data *seq = &asd_ha->seq; | ||
339 | int i, k, z = 0; | ||
340 | |||
341 | for (i = 0; i < seq->num_escbs; i++) { | ||
342 | struct asd_ascb *ascb = seq->escb_arr[i]; | ||
343 | struct empty_scb *escb = &ascb->scb->escb; | ||
344 | |||
345 | ascb->edb_index = z; | ||
346 | |||
347 | escb->num_valid = ASD_EDBS_PER_SCB; | ||
348 | |||
349 | for (k = 0; k < ASD_EDBS_PER_SCB; k++) { | ||
350 | struct sg_el *eb = &escb->eb[k]; | ||
351 | struct asd_dma_tok *edb = seq->edb_arr[z++]; | ||
352 | |||
353 | memset(eb, 0, sizeof(*eb)); | ||
354 | eb->bus_addr = cpu_to_le64(((u64) edb->dma_handle)); | ||
355 | eb->size = cpu_to_le32(((u32) edb->size)); | ||
356 | } | ||
357 | } | ||
358 | } | ||
359 | |||
360 | /** | ||
361 | * asd_init_escbs -- allocate and initialize empty scbs | ||
362 | * @asd_ha: pointer to host adapter structure | ||
363 | * | ||
364 | * An empty SCB has sg_elements of ASD_EDBS_PER_SCB (7) buffers. | ||
365 | * They transport sense data, etc. | ||
366 | */ | ||
367 | static int asd_init_escbs(struct asd_ha_struct *asd_ha) | ||
368 | { | ||
369 | struct asd_seq_data *seq = &asd_ha->seq; | ||
370 | int err = 0; | ||
371 | |||
372 | /* Allocate two empty data buffers (edb) per sequencer. */ | ||
373 | int edbs = 2*(1+asd_ha->hw_prof.num_phys); | ||
374 | |||
375 | seq->num_escbs = (edbs+ASD_EDBS_PER_SCB-1)/ASD_EDBS_PER_SCB; | ||
376 | seq->num_edbs = seq->num_escbs * ASD_EDBS_PER_SCB; | ||
377 | |||
378 | err = asd_alloc_edbs(asd_ha, GFP_KERNEL); | ||
379 | if (err) { | ||
380 | asd_printk("couldn't allocate edbs\n"); | ||
381 | return err; | ||
382 | } | ||
383 | |||
384 | err = asd_alloc_escbs(asd_ha, GFP_KERNEL); | ||
385 | if (err) { | ||
386 | asd_printk("couldn't allocate escbs\n"); | ||
387 | return err; | ||
388 | } | ||
389 | |||
390 | asd_assign_edbs2escbs(asd_ha); | ||
391 | /* In order to insure that normal SCBs do not overfill sequencer | ||
392 | * memory and leave no space for escbs (halting condition), | ||
393 | * we increment pending here by the number of escbs. However, | ||
394 | * escbs are never pending. | ||
395 | */ | ||
396 | seq->pending = seq->num_escbs; | ||
397 | seq->can_queue = 1 + (asd_ha->hw_prof.max_scbs - seq->pending)/2; | ||
398 | |||
399 | return 0; | ||
400 | } | ||
401 | |||
402 | /* ---------- HW initialization ---------- */ | ||
403 | |||
404 | /** | ||
405 | * asd_chip_hardrst -- hard reset the chip | ||
406 | * @asd_ha: pointer to host adapter structure | ||
407 | * | ||
408 | * This takes 16 cycles and is synchronous to CFCLK, which runs | ||
409 | * at 200 MHz, so this should take at most 80 nanoseconds. | ||
410 | */ | ||
411 | int asd_chip_hardrst(struct asd_ha_struct *asd_ha) | ||
412 | { | ||
413 | int i; | ||
414 | int count = 100; | ||
415 | u32 reg; | ||
416 | |||
417 | for (i = 0 ; i < 4 ; i++) { | ||
418 | asd_write_reg_dword(asd_ha, COMBIST, HARDRST); | ||
419 | } | ||
420 | |||
421 | do { | ||
422 | udelay(1); | ||
423 | reg = asd_read_reg_dword(asd_ha, CHIMINT); | ||
424 | if (reg & HARDRSTDET) { | ||
425 | asd_write_reg_dword(asd_ha, CHIMINT, | ||
426 | HARDRSTDET|PORRSTDET); | ||
427 | return 0; | ||
428 | } | ||
429 | } while (--count > 0); | ||
430 | |||
431 | return -ENODEV; | ||
432 | } | ||
433 | |||
434 | /** | ||
435 | * asd_init_chip -- initialize the chip | ||
436 | * @asd_ha: pointer to host adapter structure | ||
437 | * | ||
438 | * Hard resets the chip, disables HA interrupts, downloads the sequnecer | ||
439 | * microcode and starts the sequencers. The caller has to explicitly | ||
440 | * enable HA interrupts with asd_enable_ints(asd_ha). | ||
441 | */ | ||
442 | static int asd_init_chip(struct asd_ha_struct *asd_ha) | ||
443 | { | ||
444 | int err; | ||
445 | |||
446 | err = asd_chip_hardrst(asd_ha); | ||
447 | if (err) { | ||
448 | asd_printk("couldn't hard reset %s\n", | ||
449 | pci_name(asd_ha->pcidev)); | ||
450 | goto out; | ||
451 | } | ||
452 | |||
453 | asd_disable_ints(asd_ha); | ||
454 | |||
455 | err = asd_init_seqs(asd_ha); | ||
456 | if (err) { | ||
457 | asd_printk("couldn't init seqs for %s\n", | ||
458 | pci_name(asd_ha->pcidev)); | ||
459 | goto out; | ||
460 | } | ||
461 | |||
462 | err = asd_start_seqs(asd_ha); | ||
463 | if (err) { | ||
464 | asd_printk("coudln't start seqs for %s\n", | ||
465 | pci_name(asd_ha->pcidev)); | ||
466 | goto out; | ||
467 | } | ||
468 | out: | ||
469 | return err; | ||
470 | } | ||
471 | |||
472 | #define MAX_DEVS ((OCM_MAX_SIZE) / (ASD_DDB_SIZE)) | ||
473 | |||
474 | static int max_devs = 0; | ||
475 | module_param_named(max_devs, max_devs, int, S_IRUGO); | ||
476 | MODULE_PARM_DESC(max_devs, "\n" | ||
477 | "\tMaximum number of SAS devices to support (not LUs).\n" | ||
478 | "\tDefault: 2176, Maximum: 65663.\n"); | ||
479 | |||
480 | static int max_cmnds = 0; | ||
481 | module_param_named(max_cmnds, max_cmnds, int, S_IRUGO); | ||
482 | MODULE_PARM_DESC(max_cmnds, "\n" | ||
483 | "\tMaximum number of commands queuable.\n" | ||
484 | "\tDefault: 512, Maximum: 66047.\n"); | ||
485 | |||
486 | static void asd_extend_devctx_ocm(struct asd_ha_struct *asd_ha) | ||
487 | { | ||
488 | unsigned long dma_addr = OCM_BASE_ADDR; | ||
489 | u32 d; | ||
490 | |||
491 | dma_addr -= asd_ha->hw_prof.max_ddbs * ASD_DDB_SIZE; | ||
492 | asd_write_reg_addr(asd_ha, DEVCTXBASE, (dma_addr_t) dma_addr); | ||
493 | d = asd_read_reg_dword(asd_ha, CTXDOMAIN); | ||
494 | d |= 4; | ||
495 | asd_write_reg_dword(asd_ha, CTXDOMAIN, d); | ||
496 | asd_ha->hw_prof.max_ddbs += MAX_DEVS; | ||
497 | } | ||
498 | |||
499 | static int asd_extend_devctx(struct asd_ha_struct *asd_ha) | ||
500 | { | ||
501 | dma_addr_t dma_handle; | ||
502 | unsigned long dma_addr; | ||
503 | u32 d; | ||
504 | int size; | ||
505 | |||
506 | asd_extend_devctx_ocm(asd_ha); | ||
507 | |||
508 | asd_ha->hw_prof.ddb_ext = NULL; | ||
509 | if (max_devs <= asd_ha->hw_prof.max_ddbs || max_devs > 0xFFFF) { | ||
510 | max_devs = asd_ha->hw_prof.max_ddbs; | ||
511 | return 0; | ||
512 | } | ||
513 | |||
514 | size = (max_devs - asd_ha->hw_prof.max_ddbs + 1) * ASD_DDB_SIZE; | ||
515 | |||
516 | asd_ha->hw_prof.ddb_ext = asd_alloc_coherent(asd_ha, size, GFP_KERNEL); | ||
517 | if (!asd_ha->hw_prof.ddb_ext) { | ||
518 | asd_printk("couldn't allocate memory for %d devices\n", | ||
519 | max_devs); | ||
520 | max_devs = asd_ha->hw_prof.max_ddbs; | ||
521 | return -ENOMEM; | ||
522 | } | ||
523 | dma_handle = asd_ha->hw_prof.ddb_ext->dma_handle; | ||
524 | dma_addr = ALIGN((unsigned long) dma_handle, ASD_DDB_SIZE); | ||
525 | dma_addr -= asd_ha->hw_prof.max_ddbs * ASD_DDB_SIZE; | ||
526 | dma_handle = (dma_addr_t) dma_addr; | ||
527 | asd_write_reg_addr(asd_ha, DEVCTXBASE, dma_handle); | ||
528 | d = asd_read_reg_dword(asd_ha, CTXDOMAIN); | ||
529 | d &= ~4; | ||
530 | asd_write_reg_dword(asd_ha, CTXDOMAIN, d); | ||
531 | |||
532 | asd_ha->hw_prof.max_ddbs = max_devs; | ||
533 | |||
534 | return 0; | ||
535 | } | ||
536 | |||
537 | static int asd_extend_cmdctx(struct asd_ha_struct *asd_ha) | ||
538 | { | ||
539 | dma_addr_t dma_handle; | ||
540 | unsigned long dma_addr; | ||
541 | u32 d; | ||
542 | int size; | ||
543 | |||
544 | asd_ha->hw_prof.scb_ext = NULL; | ||
545 | if (max_cmnds <= asd_ha->hw_prof.max_scbs || max_cmnds > 0xFFFF) { | ||
546 | max_cmnds = asd_ha->hw_prof.max_scbs; | ||
547 | return 0; | ||
548 | } | ||
549 | |||
550 | size = (max_cmnds - asd_ha->hw_prof.max_scbs + 1) * ASD_SCB_SIZE; | ||
551 | |||
552 | asd_ha->hw_prof.scb_ext = asd_alloc_coherent(asd_ha, size, GFP_KERNEL); | ||
553 | if (!asd_ha->hw_prof.scb_ext) { | ||
554 | asd_printk("couldn't allocate memory for %d commands\n", | ||
555 | max_cmnds); | ||
556 | max_cmnds = asd_ha->hw_prof.max_scbs; | ||
557 | return -ENOMEM; | ||
558 | } | ||
559 | dma_handle = asd_ha->hw_prof.scb_ext->dma_handle; | ||
560 | dma_addr = ALIGN((unsigned long) dma_handle, ASD_SCB_SIZE); | ||
561 | dma_addr -= asd_ha->hw_prof.max_scbs * ASD_SCB_SIZE; | ||
562 | dma_handle = (dma_addr_t) dma_addr; | ||
563 | asd_write_reg_addr(asd_ha, CMDCTXBASE, dma_handle); | ||
564 | d = asd_read_reg_dword(asd_ha, CTXDOMAIN); | ||
565 | d &= ~1; | ||
566 | asd_write_reg_dword(asd_ha, CTXDOMAIN, d); | ||
567 | |||
568 | asd_ha->hw_prof.max_scbs = max_cmnds; | ||
569 | |||
570 | return 0; | ||
571 | } | ||
572 | |||
573 | /** | ||
574 | * asd_init_ctxmem -- initialize context memory | ||
575 | * asd_ha: pointer to host adapter structure | ||
576 | * | ||
577 | * This function sets the maximum number of SCBs and | ||
578 | * DDBs which can be used by the sequencer. This is normally | ||
579 | * 512 and 128 respectively. If support for more SCBs or more DDBs | ||
580 | * is required then CMDCTXBASE, DEVCTXBASE and CTXDOMAIN are | ||
581 | * initialized here to extend context memory to point to host memory, | ||
582 | * thus allowing unlimited support for SCBs and DDBs -- only limited | ||
583 | * by host memory. | ||
584 | */ | ||
585 | static int asd_init_ctxmem(struct asd_ha_struct *asd_ha) | ||
586 | { | ||
587 | int bitmap_bytes; | ||
588 | |||
589 | asd_get_max_scb_ddb(asd_ha); | ||
590 | asd_extend_devctx(asd_ha); | ||
591 | asd_extend_cmdctx(asd_ha); | ||
592 | |||
593 | /* The kernel wants bitmaps to be unsigned long sized. */ | ||
594 | bitmap_bytes = (asd_ha->hw_prof.max_ddbs+7)/8; | ||
595 | bitmap_bytes = BITS_TO_LONGS(bitmap_bytes*8)*sizeof(unsigned long); | ||
596 | asd_ha->hw_prof.ddb_bitmap = kzalloc(bitmap_bytes, GFP_KERNEL); | ||
597 | if (!asd_ha->hw_prof.ddb_bitmap) | ||
598 | return -ENOMEM; | ||
599 | spin_lock_init(&asd_ha->hw_prof.ddb_lock); | ||
600 | |||
601 | return 0; | ||
602 | } | ||
603 | |||
604 | int asd_init_hw(struct asd_ha_struct *asd_ha) | ||
605 | { | ||
606 | int err; | ||
607 | u32 v; | ||
608 | |||
609 | err = asd_init_sw(asd_ha); | ||
610 | if (err) | ||
611 | return err; | ||
612 | |||
613 | err = pci_read_config_dword(asd_ha->pcidev, PCIC_HSTPCIX_CNTRL, &v); | ||
614 | if (err) { | ||
615 | asd_printk("couldn't read PCIC_HSTPCIX_CNTRL of %s\n", | ||
616 | pci_name(asd_ha->pcidev)); | ||
617 | return err; | ||
618 | } | ||
619 | pci_write_config_dword(asd_ha->pcidev, PCIC_HSTPCIX_CNTRL, | ||
620 | v | SC_TMR_DIS); | ||
621 | if (err) { | ||
622 | asd_printk("couldn't disable split completion timer of %s\n", | ||
623 | pci_name(asd_ha->pcidev)); | ||
624 | return err; | ||
625 | } | ||
626 | |||
627 | err = asd_read_ocm(asd_ha); | ||
628 | if (err) { | ||
629 | asd_printk("couldn't read ocm(%d)\n", err); | ||
630 | /* While suspicios, it is not an error that we | ||
631 | * couldn't read the OCM. */ | ||
632 | } | ||
633 | |||
634 | err = asd_read_flash(asd_ha); | ||
635 | if (err) { | ||
636 | asd_printk("couldn't read flash(%d)\n", err); | ||
637 | /* While suspicios, it is not an error that we | ||
638 | * couldn't read FLASH memory. | ||
639 | */ | ||
640 | } | ||
641 | |||
642 | asd_init_ctxmem(asd_ha); | ||
643 | |||
644 | asd_get_user_sas_addr(asd_ha); | ||
645 | if (!asd_ha->hw_prof.sas_addr[0]) { | ||
646 | asd_printk("No SAS Address provided for %s\n", | ||
647 | pci_name(asd_ha->pcidev)); | ||
648 | err = -ENODEV; | ||
649 | goto Out; | ||
650 | } | ||
651 | |||
652 | asd_propagate_sas_addr(asd_ha); | ||
653 | |||
654 | err = asd_init_phys(asd_ha); | ||
655 | if (err) { | ||
656 | asd_printk("couldn't initialize phys for %s\n", | ||
657 | pci_name(asd_ha->pcidev)); | ||
658 | goto Out; | ||
659 | } | ||
660 | |||
661 | err = asd_init_scbs(asd_ha); | ||
662 | if (err) { | ||
663 | asd_printk("couldn't initialize scbs for %s\n", | ||
664 | pci_name(asd_ha->pcidev)); | ||
665 | goto Out; | ||
666 | } | ||
667 | |||
668 | err = asd_init_dl(asd_ha); | ||
669 | if (err) { | ||
670 | asd_printk("couldn't initialize the done list:%d\n", | ||
671 | err); | ||
672 | goto Out; | ||
673 | } | ||
674 | |||
675 | err = asd_init_escbs(asd_ha); | ||
676 | if (err) { | ||
677 | asd_printk("couldn't initialize escbs\n"); | ||
678 | goto Out; | ||
679 | } | ||
680 | |||
681 | err = asd_init_chip(asd_ha); | ||
682 | if (err) { | ||
683 | asd_printk("couldn't init the chip\n"); | ||
684 | goto Out; | ||
685 | } | ||
686 | Out: | ||
687 | return err; | ||
688 | } | ||
689 | |||
690 | /* ---------- Chip reset ---------- */ | ||
691 | |||
692 | /** | ||
693 | * asd_chip_reset -- reset the host adapter, etc | ||
694 | * @asd_ha: pointer to host adapter structure of interest | ||
695 | * | ||
696 | * Called from the ISR. Hard reset the chip. Let everything | ||
697 | * timeout. This should be no different than hot-unplugging the | ||
698 | * host adapter. Once everything times out we'll init the chip with | ||
699 | * a call to asd_init_chip() and enable interrupts with asd_enable_ints(). | ||
700 | * XXX finish. | ||
701 | */ | ||
702 | static void asd_chip_reset(struct asd_ha_struct *asd_ha) | ||
703 | { | ||
704 | struct sas_ha_struct *sas_ha = &asd_ha->sas_ha; | ||
705 | |||
706 | ASD_DPRINTK("chip reset for %s\n", pci_name(asd_ha->pcidev)); | ||
707 | asd_chip_hardrst(asd_ha); | ||
708 | sas_ha->notify_ha_event(sas_ha, HAE_RESET); | ||
709 | } | ||
710 | |||
711 | /* ---------- Done List Routines ---------- */ | ||
712 | |||
713 | static void asd_dl_tasklet_handler(unsigned long data) | ||
714 | { | ||
715 | struct asd_ha_struct *asd_ha = (struct asd_ha_struct *) data; | ||
716 | struct asd_seq_data *seq = &asd_ha->seq; | ||
717 | unsigned long flags; | ||
718 | |||
719 | while (1) { | ||
720 | struct done_list_struct *dl = &seq->dl[seq->dl_next]; | ||
721 | struct asd_ascb *ascb; | ||
722 | |||
723 | if ((dl->toggle & DL_TOGGLE_MASK) != seq->dl_toggle) | ||
724 | break; | ||
725 | |||
726 | /* find the aSCB */ | ||
727 | spin_lock_irqsave(&seq->tc_index_lock, flags); | ||
728 | ascb = asd_tc_index_find(seq, (int)le16_to_cpu(dl->index)); | ||
729 | spin_unlock_irqrestore(&seq->tc_index_lock, flags); | ||
730 | if (unlikely(!ascb)) { | ||
731 | ASD_DPRINTK("BUG:sequencer:dl:no ascb?!\n"); | ||
732 | goto next_1; | ||
733 | } else if (ascb->scb->header.opcode == EMPTY_SCB) { | ||
734 | goto out; | ||
735 | } else if (!ascb->uldd_timer && !del_timer(&ascb->timer)) { | ||
736 | goto next_1; | ||
737 | } | ||
738 | spin_lock_irqsave(&seq->pend_q_lock, flags); | ||
739 | list_del_init(&ascb->list); | ||
740 | seq->pending--; | ||
741 | spin_unlock_irqrestore(&seq->pend_q_lock, flags); | ||
742 | out: | ||
743 | ascb->tasklet_complete(ascb, dl); | ||
744 | |||
745 | next_1: | ||
746 | seq->dl_next = (seq->dl_next + 1) & (ASD_DL_SIZE-1); | ||
747 | if (!seq->dl_next) | ||
748 | seq->dl_toggle ^= DL_TOGGLE_MASK; | ||
749 | } | ||
750 | } | ||
751 | |||
752 | /* ---------- Interrupt Service Routines ---------- */ | ||
753 | |||
754 | /** | ||
755 | * asd_process_donelist_isr -- schedule processing of done list entries | ||
756 | * @asd_ha: pointer to host adapter structure | ||
757 | */ | ||
758 | static inline void asd_process_donelist_isr(struct asd_ha_struct *asd_ha) | ||
759 | { | ||
760 | tasklet_schedule(&asd_ha->seq.dl_tasklet); | ||
761 | } | ||
762 | |||
763 | /** | ||
764 | * asd_com_sas_isr -- process device communication interrupt (COMINT) | ||
765 | * @asd_ha: pointer to host adapter structure | ||
766 | */ | ||
767 | static inline void asd_com_sas_isr(struct asd_ha_struct *asd_ha) | ||
768 | { | ||
769 | u32 comstat = asd_read_reg_dword(asd_ha, COMSTAT); | ||
770 | |||
771 | /* clear COMSTAT int */ | ||
772 | asd_write_reg_dword(asd_ha, COMSTAT, 0xFFFFFFFF); | ||
773 | |||
774 | if (comstat & CSBUFPERR) { | ||
775 | asd_printk("%s: command/status buffer dma parity error\n", | ||
776 | pci_name(asd_ha->pcidev)); | ||
777 | } else if (comstat & CSERR) { | ||
778 | int i; | ||
779 | u32 dmaerr = asd_read_reg_dword(asd_ha, DMAERR); | ||
780 | dmaerr &= 0xFF; | ||
781 | asd_printk("%s: command/status dma error, DMAERR: 0x%02x, " | ||
782 | "CSDMAADR: 0x%04x, CSDMAADR+4: 0x%04x\n", | ||
783 | pci_name(asd_ha->pcidev), | ||
784 | dmaerr, | ||
785 | asd_read_reg_dword(asd_ha, CSDMAADR), | ||
786 | asd_read_reg_dword(asd_ha, CSDMAADR+4)); | ||
787 | asd_printk("CSBUFFER:\n"); | ||
788 | for (i = 0; i < 8; i++) { | ||
789 | asd_printk("%08x %08x %08x %08x\n", | ||
790 | asd_read_reg_dword(asd_ha, CSBUFFER), | ||
791 | asd_read_reg_dword(asd_ha, CSBUFFER+4), | ||
792 | asd_read_reg_dword(asd_ha, CSBUFFER+8), | ||
793 | asd_read_reg_dword(asd_ha, CSBUFFER+12)); | ||
794 | } | ||
795 | asd_dump_seq_state(asd_ha, 0); | ||
796 | } else if (comstat & OVLYERR) { | ||
797 | u32 dmaerr = asd_read_reg_dword(asd_ha, DMAERR); | ||
798 | dmaerr = (dmaerr >> 8) & 0xFF; | ||
799 | asd_printk("%s: overlay dma error:0x%x\n", | ||
800 | pci_name(asd_ha->pcidev), | ||
801 | dmaerr); | ||
802 | } | ||
803 | asd_chip_reset(asd_ha); | ||
804 | } | ||
805 | |||
806 | static inline void asd_arp2_err(struct asd_ha_struct *asd_ha, u32 dchstatus) | ||
807 | { | ||
808 | static const char *halt_code[256] = { | ||
809 | "UNEXPECTED_INTERRUPT0", | ||
810 | "UNEXPECTED_INTERRUPT1", | ||
811 | "UNEXPECTED_INTERRUPT2", | ||
812 | "UNEXPECTED_INTERRUPT3", | ||
813 | "UNEXPECTED_INTERRUPT4", | ||
814 | "UNEXPECTED_INTERRUPT5", | ||
815 | "UNEXPECTED_INTERRUPT6", | ||
816 | "UNEXPECTED_INTERRUPT7", | ||
817 | "UNEXPECTED_INTERRUPT8", | ||
818 | "UNEXPECTED_INTERRUPT9", | ||
819 | "UNEXPECTED_INTERRUPT10", | ||
820 | [11 ... 19] = "unknown[11,19]", | ||
821 | "NO_FREE_SCB_AVAILABLE", | ||
822 | "INVALID_SCB_OPCODE", | ||
823 | "INVALID_MBX_OPCODE", | ||
824 | "INVALID_ATA_STATE", | ||
825 | "ATA_QUEUE_FULL", | ||
826 | "ATA_TAG_TABLE_FAULT", | ||
827 | "ATA_TAG_MASK_FAULT", | ||
828 | "BAD_LINK_QUEUE_STATE", | ||
829 | "DMA2CHIM_QUEUE_ERROR", | ||
830 | "EMPTY_SCB_LIST_FULL", | ||
831 | "unknown[30]", | ||
832 | "IN_USE_SCB_ON_FREE_LIST", | ||
833 | "BAD_OPEN_WAIT_STATE", | ||
834 | "INVALID_STP_AFFILIATION", | ||
835 | "unknown[34]", | ||
836 | "EXEC_QUEUE_ERROR", | ||
837 | "TOO_MANY_EMPTIES_NEEDED", | ||
838 | "EMPTY_REQ_QUEUE_ERROR", | ||
839 | "Q_MONIRTT_MGMT_ERROR", | ||
840 | "TARGET_MODE_FLOW_ERROR", | ||
841 | "DEVICE_QUEUE_NOT_FOUND", | ||
842 | "START_IRTT_TIMER_ERROR", | ||
843 | "ABORT_TASK_ILLEGAL_REQ", | ||
844 | [43 ... 255] = "unknown[43,255]" | ||
845 | }; | ||
846 | |||
847 | if (dchstatus & CSEQINT) { | ||
848 | u32 arp2int = asd_read_reg_dword(asd_ha, CARP2INT); | ||
849 | |||
850 | if (arp2int & (ARP2WAITTO|ARP2ILLOPC|ARP2PERR|ARP2CIOPERR)) { | ||
851 | asd_printk("%s: CSEQ arp2int:0x%x\n", | ||
852 | pci_name(asd_ha->pcidev), | ||
853 | arp2int); | ||
854 | } else if (arp2int & ARP2HALTC) | ||
855 | asd_printk("%s: CSEQ halted: %s\n", | ||
856 | pci_name(asd_ha->pcidev), | ||
857 | halt_code[(arp2int>>16)&0xFF]); | ||
858 | else | ||
859 | asd_printk("%s: CARP2INT:0x%x\n", | ||
860 | pci_name(asd_ha->pcidev), | ||
861 | arp2int); | ||
862 | } | ||
863 | if (dchstatus & LSEQINT_MASK) { | ||
864 | int lseq; | ||
865 | u8 lseq_mask = dchstatus & LSEQINT_MASK; | ||
866 | |||
867 | for_each_sequencer(lseq_mask, lseq_mask, lseq) { | ||
868 | u32 arp2int = asd_read_reg_dword(asd_ha, | ||
869 | LmARP2INT(lseq)); | ||
870 | if (arp2int & (ARP2WAITTO | ARP2ILLOPC | ARP2PERR | ||
871 | | ARP2CIOPERR)) { | ||
872 | asd_printk("%s: LSEQ%d arp2int:0x%x\n", | ||
873 | pci_name(asd_ha->pcidev), | ||
874 | lseq, arp2int); | ||
875 | /* XXX we should only do lseq reset */ | ||
876 | } else if (arp2int & ARP2HALTC) | ||
877 | asd_printk("%s: LSEQ%d halted: %s\n", | ||
878 | pci_name(asd_ha->pcidev), | ||
879 | lseq,halt_code[(arp2int>>16)&0xFF]); | ||
880 | else | ||
881 | asd_printk("%s: LSEQ%d ARP2INT:0x%x\n", | ||
882 | pci_name(asd_ha->pcidev), lseq, | ||
883 | arp2int); | ||
884 | } | ||
885 | } | ||
886 | asd_chip_reset(asd_ha); | ||
887 | } | ||
888 | |||
889 | /** | ||
890 | * asd_dch_sas_isr -- process device channel interrupt (DEVINT) | ||
891 | * @asd_ha: pointer to host adapter structure | ||
892 | */ | ||
893 | static inline void asd_dch_sas_isr(struct asd_ha_struct *asd_ha) | ||
894 | { | ||
895 | u32 dchstatus = asd_read_reg_dword(asd_ha, DCHSTATUS); | ||
896 | |||
897 | if (dchstatus & CFIFTOERR) { | ||
898 | asd_printk("%s: CFIFTOERR\n", pci_name(asd_ha->pcidev)); | ||
899 | asd_chip_reset(asd_ha); | ||
900 | } else | ||
901 | asd_arp2_err(asd_ha, dchstatus); | ||
902 | } | ||
903 | |||
904 | /** | ||
905 | * ads_rbi_exsi_isr -- process external system interface interrupt (INITERR) | ||
906 | * @asd_ha: pointer to host adapter structure | ||
907 | */ | ||
908 | static inline void asd_rbi_exsi_isr(struct asd_ha_struct *asd_ha) | ||
909 | { | ||
910 | u32 stat0r = asd_read_reg_dword(asd_ha, ASISTAT0R); | ||
911 | |||
912 | if (!(stat0r & ASIERR)) { | ||
913 | asd_printk("hmm, EXSI interrupted but no error?\n"); | ||
914 | return; | ||
915 | } | ||
916 | |||
917 | if (stat0r & ASIFMTERR) { | ||
918 | asd_printk("ASI SEEPROM format error for %s\n", | ||
919 | pci_name(asd_ha->pcidev)); | ||
920 | } else if (stat0r & ASISEECHKERR) { | ||
921 | u32 stat1r = asd_read_reg_dword(asd_ha, ASISTAT1R); | ||
922 | asd_printk("ASI SEEPROM checksum 0x%x error for %s\n", | ||
923 | stat1r & CHECKSUM_MASK, | ||
924 | pci_name(asd_ha->pcidev)); | ||
925 | } else { | ||
926 | u32 statr = asd_read_reg_dword(asd_ha, ASIERRSTATR); | ||
927 | |||
928 | if (!(statr & CPI2ASIMSTERR_MASK)) { | ||
929 | ASD_DPRINTK("hmm, ASIERR?\n"); | ||
930 | return; | ||
931 | } else { | ||
932 | u32 addr = asd_read_reg_dword(asd_ha, ASIERRADDR); | ||
933 | u32 data = asd_read_reg_dword(asd_ha, ASIERRDATAR); | ||
934 | |||
935 | asd_printk("%s: CPI2 xfer err: addr: 0x%x, wdata: 0x%x, " | ||
936 | "count: 0x%x, byteen: 0x%x, targerr: 0x%x " | ||
937 | "master id: 0x%x, master err: 0x%x\n", | ||
938 | pci_name(asd_ha->pcidev), | ||
939 | addr, data, | ||
940 | (statr & CPI2ASIBYTECNT_MASK) >> 16, | ||
941 | (statr & CPI2ASIBYTEEN_MASK) >> 12, | ||
942 | (statr & CPI2ASITARGERR_MASK) >> 8, | ||
943 | (statr & CPI2ASITARGMID_MASK) >> 4, | ||
944 | (statr & CPI2ASIMSTERR_MASK)); | ||
945 | } | ||
946 | } | ||
947 | asd_chip_reset(asd_ha); | ||
948 | } | ||
949 | |||
950 | /** | ||
951 | * asd_hst_pcix_isr -- process host interface interrupts | ||
952 | * @asd_ha: pointer to host adapter structure | ||
953 | * | ||
954 | * Asserted on PCIX errors: target abort, etc. | ||
955 | */ | ||
956 | static inline void asd_hst_pcix_isr(struct asd_ha_struct *asd_ha) | ||
957 | { | ||
958 | u16 status; | ||
959 | u32 pcix_status; | ||
960 | u32 ecc_status; | ||
961 | |||
962 | pci_read_config_word(asd_ha->pcidev, PCI_STATUS, &status); | ||
963 | pci_read_config_dword(asd_ha->pcidev, PCIX_STATUS, &pcix_status); | ||
964 | pci_read_config_dword(asd_ha->pcidev, ECC_CTRL_STAT, &ecc_status); | ||
965 | |||
966 | if (status & PCI_STATUS_DETECTED_PARITY) | ||
967 | asd_printk("parity error for %s\n", pci_name(asd_ha->pcidev)); | ||
968 | else if (status & PCI_STATUS_REC_MASTER_ABORT) | ||
969 | asd_printk("master abort for %s\n", pci_name(asd_ha->pcidev)); | ||
970 | else if (status & PCI_STATUS_REC_TARGET_ABORT) | ||
971 | asd_printk("target abort for %s\n", pci_name(asd_ha->pcidev)); | ||
972 | else if (status & PCI_STATUS_PARITY) | ||
973 | asd_printk("data parity for %s\n", pci_name(asd_ha->pcidev)); | ||
974 | else if (pcix_status & RCV_SCE) { | ||
975 | asd_printk("received split completion error for %s\n", | ||
976 | pci_name(asd_ha->pcidev)); | ||
977 | pci_write_config_dword(asd_ha->pcidev,PCIX_STATUS,pcix_status); | ||
978 | /* XXX: Abort task? */ | ||
979 | return; | ||
980 | } else if (pcix_status & UNEXP_SC) { | ||
981 | asd_printk("unexpected split completion for %s\n", | ||
982 | pci_name(asd_ha->pcidev)); | ||
983 | pci_write_config_dword(asd_ha->pcidev,PCIX_STATUS,pcix_status); | ||
984 | /* ignore */ | ||
985 | return; | ||
986 | } else if (pcix_status & SC_DISCARD) | ||
987 | asd_printk("split completion discarded for %s\n", | ||
988 | pci_name(asd_ha->pcidev)); | ||
989 | else if (ecc_status & UNCOR_ECCERR) | ||
990 | asd_printk("uncorrectable ECC error for %s\n", | ||
991 | pci_name(asd_ha->pcidev)); | ||
992 | asd_chip_reset(asd_ha); | ||
993 | } | ||
994 | |||
995 | /** | ||
996 | * asd_hw_isr -- host adapter interrupt service routine | ||
997 | * @irq: ignored | ||
998 | * @dev_id: pointer to host adapter structure | ||
999 | * @regs: ignored | ||
1000 | * | ||
1001 | * The ISR processes done list entries and level 3 error handling. | ||
1002 | */ | ||
1003 | irqreturn_t asd_hw_isr(int irq, void *dev_id, struct pt_regs *regs) | ||
1004 | { | ||
1005 | struct asd_ha_struct *asd_ha = dev_id; | ||
1006 | u32 chimint = asd_read_reg_dword(asd_ha, CHIMINT); | ||
1007 | |||
1008 | if (!chimint) | ||
1009 | return IRQ_NONE; | ||
1010 | |||
1011 | asd_write_reg_dword(asd_ha, CHIMINT, chimint); | ||
1012 | (void) asd_read_reg_dword(asd_ha, CHIMINT); | ||
1013 | |||
1014 | if (chimint & DLAVAIL) | ||
1015 | asd_process_donelist_isr(asd_ha); | ||
1016 | if (chimint & COMINT) | ||
1017 | asd_com_sas_isr(asd_ha); | ||
1018 | if (chimint & DEVINT) | ||
1019 | asd_dch_sas_isr(asd_ha); | ||
1020 | if (chimint & INITERR) | ||
1021 | asd_rbi_exsi_isr(asd_ha); | ||
1022 | if (chimint & HOSTERR) | ||
1023 | asd_hst_pcix_isr(asd_ha); | ||
1024 | |||
1025 | return IRQ_HANDLED; | ||
1026 | } | ||
1027 | |||
1028 | /* ---------- SCB handling ---------- */ | ||
1029 | |||
1030 | static inline struct asd_ascb *asd_ascb_alloc(struct asd_ha_struct *asd_ha, | ||
1031 | unsigned int gfp_flags) | ||
1032 | { | ||
1033 | extern kmem_cache_t *asd_ascb_cache; | ||
1034 | struct asd_seq_data *seq = &asd_ha->seq; | ||
1035 | struct asd_ascb *ascb; | ||
1036 | unsigned long flags; | ||
1037 | |||
1038 | ascb = kmem_cache_alloc(asd_ascb_cache, gfp_flags); | ||
1039 | |||
1040 | if (ascb) { | ||
1041 | memset(ascb, 0, sizeof(*ascb)); | ||
1042 | ascb->dma_scb.size = sizeof(struct scb); | ||
1043 | ascb->dma_scb.vaddr = dma_pool_alloc(asd_ha->scb_pool, | ||
1044 | gfp_flags, | ||
1045 | &ascb->dma_scb.dma_handle); | ||
1046 | if (!ascb->dma_scb.vaddr) { | ||
1047 | kmem_cache_free(asd_ascb_cache, ascb); | ||
1048 | return NULL; | ||
1049 | } | ||
1050 | memset(ascb->dma_scb.vaddr, 0, sizeof(struct scb)); | ||
1051 | asd_init_ascb(asd_ha, ascb); | ||
1052 | |||
1053 | spin_lock_irqsave(&seq->tc_index_lock, flags); | ||
1054 | ascb->tc_index = asd_tc_index_get(seq, ascb); | ||
1055 | spin_unlock_irqrestore(&seq->tc_index_lock, flags); | ||
1056 | if (ascb->tc_index == -1) | ||
1057 | goto undo; | ||
1058 | |||
1059 | ascb->scb->header.index = cpu_to_le16((u16)ascb->tc_index); | ||
1060 | } | ||
1061 | |||
1062 | return ascb; | ||
1063 | undo: | ||
1064 | dma_pool_free(asd_ha->scb_pool, ascb->dma_scb.vaddr, | ||
1065 | ascb->dma_scb.dma_handle); | ||
1066 | kmem_cache_free(asd_ascb_cache, ascb); | ||
1067 | ASD_DPRINTK("no index for ascb\n"); | ||
1068 | return NULL; | ||
1069 | } | ||
1070 | |||
1071 | /** | ||
1072 | * asd_ascb_alloc_list -- allocate a list of aSCBs | ||
1073 | * @asd_ha: pointer to host adapter structure | ||
1074 | * @num: pointer to integer number of aSCBs | ||
1075 | * @gfp_flags: GFP_ flags. | ||
1076 | * | ||
1077 | * This is the only function which is used to allocate aSCBs. | ||
1078 | * It can allocate one or many. If more than one, then they form | ||
1079 | * a linked list in two ways: by their list field of the ascb struct | ||
1080 | * and by the next_scb field of the scb_header. | ||
1081 | * | ||
1082 | * Returns NULL if no memory was available, else pointer to a list | ||
1083 | * of ascbs. When this function returns, @num would be the number | ||
1084 | * of SCBs which were not able to be allocated, 0 if all requested | ||
1085 | * were able to be allocated. | ||
1086 | */ | ||
1087 | struct asd_ascb *asd_ascb_alloc_list(struct asd_ha_struct | ||
1088 | *asd_ha, int *num, | ||
1089 | unsigned int gfp_flags) | ||
1090 | { | ||
1091 | struct asd_ascb *first = NULL; | ||
1092 | |||
1093 | for ( ; *num > 0; --*num) { | ||
1094 | struct asd_ascb *ascb = asd_ascb_alloc(asd_ha, gfp_flags); | ||
1095 | |||
1096 | if (!ascb) | ||
1097 | break; | ||
1098 | else if (!first) | ||
1099 | first = ascb; | ||
1100 | else { | ||
1101 | struct asd_ascb *last = list_entry(first->list.prev, | ||
1102 | struct asd_ascb, | ||
1103 | list); | ||
1104 | list_add_tail(&ascb->list, &first->list); | ||
1105 | last->scb->header.next_scb = | ||
1106 | cpu_to_le64(((u64)ascb->dma_scb.dma_handle)); | ||
1107 | } | ||
1108 | } | ||
1109 | |||
1110 | return first; | ||
1111 | } | ||
1112 | |||
1113 | /** | ||
1114 | * asd_swap_head_scb -- swap the head scb | ||
1115 | * @asd_ha: pointer to host adapter structure | ||
1116 | * @ascb: pointer to the head of an ascb list | ||
1117 | * | ||
1118 | * The sequencer knows the DMA address of the next SCB to be DMAed to | ||
1119 | * the host adapter, from initialization or from the last list DMAed. | ||
1120 | * seq->next_scb keeps the address of this SCB. The sequencer will | ||
1121 | * DMA to the host adapter this list of SCBs. But the head (first | ||
1122 | * element) of this list is not known to the sequencer. Here we swap | ||
1123 | * the head of the list with the known SCB (memcpy()). | ||
1124 | * Only one memcpy() is required per list so it is in our interest | ||
1125 | * to keep the list of SCB as long as possible so that the ratio | ||
1126 | * of number of memcpy calls to the number of SCB DMA-ed is as small | ||
1127 | * as possible. | ||
1128 | * | ||
1129 | * LOCKING: called with the pending list lock held. | ||
1130 | */ | ||
1131 | static inline void asd_swap_head_scb(struct asd_ha_struct *asd_ha, | ||
1132 | struct asd_ascb *ascb) | ||
1133 | { | ||
1134 | struct asd_seq_data *seq = &asd_ha->seq; | ||
1135 | struct asd_ascb *last = list_entry(ascb->list.prev, | ||
1136 | struct asd_ascb, | ||
1137 | list); | ||
1138 | struct asd_dma_tok t = ascb->dma_scb; | ||
1139 | |||
1140 | memcpy(seq->next_scb.vaddr, ascb->scb, sizeof(*ascb->scb)); | ||
1141 | ascb->dma_scb = seq->next_scb; | ||
1142 | ascb->scb = ascb->dma_scb.vaddr; | ||
1143 | seq->next_scb = t; | ||
1144 | last->scb->header.next_scb = | ||
1145 | cpu_to_le64(((u64)seq->next_scb.dma_handle)); | ||
1146 | } | ||
1147 | |||
1148 | /** | ||
1149 | * asd_start_timers -- (add and) start timers of SCBs | ||
1150 | * @list: pointer to struct list_head of the scbs | ||
1151 | * @to: timeout in jiffies | ||
1152 | * | ||
1153 | * If an SCB in the @list has no timer function, assign the default | ||
1154 | * one, then start the timer of the SCB. This function is | ||
1155 | * intended to be called from asd_post_ascb_list(), just prior to | ||
1156 | * posting the SCBs to the sequencer. | ||
1157 | */ | ||
1158 | static inline void asd_start_scb_timers(struct list_head *list) | ||
1159 | { | ||
1160 | struct asd_ascb *ascb; | ||
1161 | list_for_each_entry(ascb, list, list) { | ||
1162 | if (!ascb->uldd_timer) { | ||
1163 | ascb->timer.data = (unsigned long) ascb; | ||
1164 | ascb->timer.function = asd_ascb_timedout; | ||
1165 | ascb->timer.expires = jiffies + AIC94XX_SCB_TIMEOUT; | ||
1166 | add_timer(&ascb->timer); | ||
1167 | } | ||
1168 | } | ||
1169 | } | ||
1170 | |||
1171 | /** | ||
1172 | * asd_post_ascb_list -- post a list of 1 or more aSCBs to the host adapter | ||
1173 | * @asd_ha: pointer to a host adapter structure | ||
1174 | * @ascb: pointer to the first aSCB in the list | ||
1175 | * @num: number of aSCBs in the list (to be posted) | ||
1176 | * | ||
1177 | * See queueing comment in asd_post_escb_list(). | ||
1178 | * | ||
1179 | * Additional note on queuing: In order to minimize the ratio of memcpy() | ||
1180 | * to the number of ascbs sent, we try to batch-send as many ascbs as possible | ||
1181 | * in one go. | ||
1182 | * Two cases are possible: | ||
1183 | * A) can_queue >= num, | ||
1184 | * B) can_queue < num. | ||
1185 | * Case A: we can send the whole batch at once. Increment "pending" | ||
1186 | * in the beginning of this function, when it is checked, in order to | ||
1187 | * eliminate races when this function is called by multiple processes. | ||
1188 | * Case B: should never happen if the managing layer considers | ||
1189 | * lldd_queue_size. | ||
1190 | */ | ||
1191 | int asd_post_ascb_list(struct asd_ha_struct *asd_ha, struct asd_ascb *ascb, | ||
1192 | int num) | ||
1193 | { | ||
1194 | unsigned long flags; | ||
1195 | LIST_HEAD(list); | ||
1196 | int can_queue; | ||
1197 | |||
1198 | spin_lock_irqsave(&asd_ha->seq.pend_q_lock, flags); | ||
1199 | can_queue = asd_ha->hw_prof.max_scbs - asd_ha->seq.pending; | ||
1200 | if (can_queue >= num) | ||
1201 | asd_ha->seq.pending += num; | ||
1202 | else | ||
1203 | can_queue = 0; | ||
1204 | |||
1205 | if (!can_queue) { | ||
1206 | spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags); | ||
1207 | asd_printk("%s: scb queue full\n", pci_name(asd_ha->pcidev)); | ||
1208 | return -SAS_QUEUE_FULL; | ||
1209 | } | ||
1210 | |||
1211 | asd_swap_head_scb(asd_ha, ascb); | ||
1212 | |||
1213 | __list_add(&list, ascb->list.prev, &ascb->list); | ||
1214 | |||
1215 | asd_start_scb_timers(&list); | ||
1216 | |||
1217 | asd_ha->seq.scbpro += num; | ||
1218 | list_splice_init(&list, asd_ha->seq.pend_q.prev); | ||
1219 | asd_write_reg_dword(asd_ha, SCBPRO, (u32)asd_ha->seq.scbpro); | ||
1220 | spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags); | ||
1221 | |||
1222 | return 0; | ||
1223 | } | ||
1224 | |||
1225 | /** | ||
1226 | * asd_post_escb_list -- post a list of 1 or more empty scb | ||
1227 | * @asd_ha: pointer to a host adapter structure | ||
1228 | * @ascb: pointer to the first empty SCB in the list | ||
1229 | * @num: number of aSCBs in the list (to be posted) | ||
1230 | * | ||
1231 | * This is essentially the same as asd_post_ascb_list, but we do not | ||
1232 | * increment pending, add those to the pending list or get indexes. | ||
1233 | * See asd_init_escbs() and asd_init_post_escbs(). | ||
1234 | * | ||
1235 | * Since sending a list of ascbs is a superset of sending a single | ||
1236 | * ascb, this function exists to generalize this. More specifically, | ||
1237 | * when sending a list of those, we want to do only a _single_ | ||
1238 | * memcpy() at swap head, as opposed to for each ascb sent (in the | ||
1239 | * case of sending them one by one). That is, we want to minimize the | ||
1240 | * ratio of memcpy() operations to the number of ascbs sent. The same | ||
1241 | * logic applies to asd_post_ascb_list(). | ||
1242 | */ | ||
1243 | int asd_post_escb_list(struct asd_ha_struct *asd_ha, struct asd_ascb *ascb, | ||
1244 | int num) | ||
1245 | { | ||
1246 | unsigned long flags; | ||
1247 | |||
1248 | spin_lock_irqsave(&asd_ha->seq.pend_q_lock, flags); | ||
1249 | asd_swap_head_scb(asd_ha, ascb); | ||
1250 | asd_ha->seq.scbpro += num; | ||
1251 | asd_write_reg_dword(asd_ha, SCBPRO, (u32)asd_ha->seq.scbpro); | ||
1252 | spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags); | ||
1253 | |||
1254 | return 0; | ||
1255 | } | ||
1256 | |||
1257 | /* ---------- LED ---------- */ | ||
1258 | |||
1259 | /** | ||
1260 | * asd_turn_led -- turn on/off an LED | ||
1261 | * @asd_ha: pointer to host adapter structure | ||
1262 | * @phy_id: the PHY id whose LED we want to manupulate | ||
1263 | * @op: 1 to turn on, 0 to turn off | ||
1264 | */ | ||
1265 | void asd_turn_led(struct asd_ha_struct *asd_ha, int phy_id, int op) | ||
1266 | { | ||
1267 | if (phy_id < ASD_MAX_PHYS) { | ||
1268 | u32 v = asd_read_reg_dword(asd_ha, LmCONTROL(phy_id)); | ||
1269 | if (op) | ||
1270 | v |= LEDPOL; | ||
1271 | else | ||
1272 | v &= ~LEDPOL; | ||
1273 | asd_write_reg_dword(asd_ha, LmCONTROL(phy_id), v); | ||
1274 | } | ||
1275 | } | ||
1276 | |||
1277 | /** | ||
1278 | * asd_control_led -- enable/disable an LED on the board | ||
1279 | * @asd_ha: pointer to host adapter structure | ||
1280 | * @phy_id: integer, the phy id | ||
1281 | * @op: integer, 1 to enable, 0 to disable the LED | ||
1282 | * | ||
1283 | * First we output enable the LED, then we set the source | ||
1284 | * to be an external module. | ||
1285 | */ | ||
1286 | void asd_control_led(struct asd_ha_struct *asd_ha, int phy_id, int op) | ||
1287 | { | ||
1288 | if (phy_id < ASD_MAX_PHYS) { | ||
1289 | u32 v; | ||
1290 | |||
1291 | v = asd_read_reg_dword(asd_ha, GPIOOER); | ||
1292 | if (op) | ||
1293 | v |= (1 << phy_id); | ||
1294 | else | ||
1295 | v &= ~(1 << phy_id); | ||
1296 | asd_write_reg_dword(asd_ha, GPIOOER, v); | ||
1297 | |||
1298 | v = asd_read_reg_dword(asd_ha, GPIOCNFGR); | ||
1299 | if (op) | ||
1300 | v |= (1 << phy_id); | ||
1301 | else | ||
1302 | v &= ~(1 << phy_id); | ||
1303 | asd_write_reg_dword(asd_ha, GPIOCNFGR, v); | ||
1304 | } | ||
1305 | } | ||
1306 | |||
1307 | /* ---------- PHY enable ---------- */ | ||
1308 | |||
1309 | static int asd_enable_phy(struct asd_ha_struct *asd_ha, int phy_id) | ||
1310 | { | ||
1311 | struct asd_phy *phy = &asd_ha->phys[phy_id]; | ||
1312 | |||
1313 | asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, INT_ENABLE_2), 0); | ||
1314 | asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, HOT_PLUG_DELAY), | ||
1315 | HOTPLUG_DELAY_TIMEOUT); | ||
1316 | |||
1317 | /* Get defaults from manuf. sector */ | ||
1318 | /* XXX we need defaults for those in case MS is broken. */ | ||
1319 | asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, PHY_CONTROL_0), | ||
1320 | phy->phy_desc->phy_control_0); | ||
1321 | asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, PHY_CONTROL_1), | ||
1322 | phy->phy_desc->phy_control_1); | ||
1323 | asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, PHY_CONTROL_2), | ||
1324 | phy->phy_desc->phy_control_2); | ||
1325 | asd_write_reg_byte(asd_ha, LmSEQ_OOB_REG(phy_id, PHY_CONTROL_3), | ||
1326 | phy->phy_desc->phy_control_3); | ||
1327 | |||
1328 | asd_write_reg_dword(asd_ha, LmSEQ_TEN_MS_COMINIT_TIMEOUT(phy_id), | ||
1329 | ASD_COMINIT_TIMEOUT); | ||
1330 | |||
1331 | asd_write_reg_addr(asd_ha, LmSEQ_TX_ID_ADDR_FRAME(phy_id), | ||
1332 | phy->id_frm_tok->dma_handle); | ||
1333 | |||
1334 | asd_control_led(asd_ha, phy_id, 1); | ||
1335 | |||
1336 | return 0; | ||
1337 | } | ||
1338 | |||
1339 | int asd_enable_phys(struct asd_ha_struct *asd_ha, const u8 phy_mask) | ||
1340 | { | ||
1341 | u8 phy_m; | ||
1342 | u8 i; | ||
1343 | int num = 0, k; | ||
1344 | struct asd_ascb *ascb; | ||
1345 | struct asd_ascb *ascb_list; | ||
1346 | |||
1347 | if (!phy_mask) { | ||
1348 | asd_printk("%s called with phy_mask of 0!?\n", __FUNCTION__); | ||
1349 | return 0; | ||
1350 | } | ||
1351 | |||
1352 | for_each_phy(phy_mask, phy_m, i) { | ||
1353 | num++; | ||
1354 | asd_enable_phy(asd_ha, i); | ||
1355 | } | ||
1356 | |||
1357 | k = num; | ||
1358 | ascb_list = asd_ascb_alloc_list(asd_ha, &k, GFP_KERNEL); | ||
1359 | if (!ascb_list) { | ||
1360 | asd_printk("no memory for control phy ascb list\n"); | ||
1361 | return -ENOMEM; | ||
1362 | } | ||
1363 | num -= k; | ||
1364 | |||
1365 | ascb = ascb_list; | ||
1366 | for_each_phy(phy_mask, phy_m, i) { | ||
1367 | asd_build_control_phy(ascb, i, ENABLE_PHY); | ||
1368 | ascb = list_entry(ascb->list.next, struct asd_ascb, list); | ||
1369 | } | ||
1370 | ASD_DPRINTK("posting %d control phy scbs\n", num); | ||
1371 | k = asd_post_ascb_list(asd_ha, ascb_list, num); | ||
1372 | if (k) | ||
1373 | asd_ascb_free_list(ascb_list); | ||
1374 | |||
1375 | return k; | ||
1376 | } | ||
diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.h b/drivers/scsi/aic94xx/aic94xx_hwi.h new file mode 100644 index 000000000000..c7d505388fed --- /dev/null +++ b/drivers/scsi/aic94xx/aic94xx_hwi.h | |||
@@ -0,0 +1,397 @@ | |||
1 | /* | ||
2 | * Aic94xx SAS/SATA driver hardware interface header file. | ||
3 | * | ||
4 | * Copyright (C) 2005 Adaptec, Inc. All rights reserved. | ||
5 | * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> | ||
6 | * | ||
7 | * This file is licensed under GPLv2. | ||
8 | * | ||
9 | * This file is part of the aic94xx driver. | ||
10 | * | ||
11 | * The aic94xx driver is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License as | ||
13 | * published by the Free Software Foundation; version 2 of the | ||
14 | * License. | ||
15 | * | ||
16 | * The aic94xx driver is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
19 | * General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with the aic94xx driver; if not, write to the Free Software | ||
23 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #ifndef _AIC94XX_HWI_H_ | ||
28 | #define _AIC94XX_HWI_H_ | ||
29 | |||
30 | #include <linux/interrupt.h> | ||
31 | #include <linux/pci.h> | ||
32 | #include <linux/dma-mapping.h> | ||
33 | |||
34 | #include <scsi/libsas.h> | ||
35 | |||
36 | #include "aic94xx.h" | ||
37 | #include "aic94xx_sas.h" | ||
38 | |||
39 | /* Define ASD_MAX_PHYS to the maximum phys ever. Currently 8. */ | ||
40 | #define ASD_MAX_PHYS 8 | ||
41 | #define ASD_PCBA_SN_SIZE 12 | ||
42 | |||
43 | /* Those are to be further named properly, the "RAZORx" part, and | ||
44 | * subsequently included in include/linux/pci_ids.h. | ||
45 | */ | ||
46 | #define PCI_DEVICE_ID_ADAPTEC2_RAZOR10 0x410 | ||
47 | #define PCI_DEVICE_ID_ADAPTEC2_RAZOR12 0x412 | ||
48 | #define PCI_DEVICE_ID_ADAPTEC2_RAZOR1E 0x41E | ||
49 | #define PCI_DEVICE_ID_ADAPTEC2_RAZOR30 0x430 | ||
50 | #define PCI_DEVICE_ID_ADAPTEC2_RAZOR32 0x432 | ||
51 | #define PCI_DEVICE_ID_ADAPTEC2_RAZOR3E 0x43E | ||
52 | #define PCI_DEVICE_ID_ADAPTEC2_RAZOR3F 0x43F | ||
53 | |||
54 | struct asd_ha_addrspace { | ||
55 | void __iomem *addr; | ||
56 | unsigned long start; /* pci resource start */ | ||
57 | unsigned long len; /* pci resource len */ | ||
58 | unsigned long flags; /* pci resource flags */ | ||
59 | |||
60 | /* addresses internal to the host adapter */ | ||
61 | u32 swa_base; /* mmspace 1 (MBAR1) uses this only */ | ||
62 | u32 swb_base; | ||
63 | u32 swc_base; | ||
64 | }; | ||
65 | |||
66 | struct bios_struct { | ||
67 | int present; | ||
68 | u8 maj; | ||
69 | u8 min; | ||
70 | u32 bld; | ||
71 | }; | ||
72 | |||
73 | struct unit_element_struct { | ||
74 | u16 num; | ||
75 | u16 size; | ||
76 | void *area; | ||
77 | }; | ||
78 | |||
79 | struct flash_struct { | ||
80 | u32 bar; | ||
81 | int present; | ||
82 | int wide; | ||
83 | u8 manuf; | ||
84 | u8 dev_id; | ||
85 | u8 sec_prot; | ||
86 | |||
87 | u32 dir_offs; | ||
88 | }; | ||
89 | |||
90 | struct asd_phy_desc { | ||
91 | /* From CTRL-A settings, then set to what is appropriate */ | ||
92 | u8 sas_addr[SAS_ADDR_SIZE]; | ||
93 | u8 max_sas_lrate; | ||
94 | u8 min_sas_lrate; | ||
95 | u8 max_sata_lrate; | ||
96 | u8 min_sata_lrate; | ||
97 | u8 flags; | ||
98 | #define ASD_CRC_DIS 1 | ||
99 | #define ASD_SATA_SPINUP_HOLD 2 | ||
100 | |||
101 | u8 phy_control_0; /* mode 5 reg 0x160 */ | ||
102 | u8 phy_control_1; /* mode 5 reg 0x161 */ | ||
103 | u8 phy_control_2; /* mode 5 reg 0x162 */ | ||
104 | u8 phy_control_3; /* mode 5 reg 0x163 */ | ||
105 | }; | ||
106 | |||
107 | struct asd_dma_tok { | ||
108 | void *vaddr; | ||
109 | dma_addr_t dma_handle; | ||
110 | size_t size; | ||
111 | }; | ||
112 | |||
113 | struct hw_profile { | ||
114 | struct bios_struct bios; | ||
115 | struct unit_element_struct ue; | ||
116 | struct flash_struct flash; | ||
117 | |||
118 | u8 sas_addr[SAS_ADDR_SIZE]; | ||
119 | char pcba_sn[ASD_PCBA_SN_SIZE+1]; | ||
120 | |||
121 | u8 enabled_phys; /* mask of enabled phys */ | ||
122 | struct asd_phy_desc phy_desc[ASD_MAX_PHYS]; | ||
123 | u32 max_scbs; /* absolute sequencer scb queue size */ | ||
124 | struct asd_dma_tok *scb_ext; | ||
125 | u32 max_ddbs; | ||
126 | struct asd_dma_tok *ddb_ext; | ||
127 | |||
128 | spinlock_t ddb_lock; | ||
129 | void *ddb_bitmap; | ||
130 | |||
131 | int num_phys; /* ENABLEABLE */ | ||
132 | int max_phys; /* REPORTED + ENABLEABLE */ | ||
133 | |||
134 | unsigned addr_range; /* max # of addrs; max # of possible ports */ | ||
135 | unsigned port_name_base; | ||
136 | unsigned dev_name_base; | ||
137 | unsigned sata_name_base; | ||
138 | }; | ||
139 | |||
140 | struct asd_ascb { | ||
141 | struct list_head list; | ||
142 | struct asd_ha_struct *ha; | ||
143 | |||
144 | struct scb *scb; /* equals dma_scb->vaddr */ | ||
145 | struct asd_dma_tok dma_scb; | ||
146 | struct asd_dma_tok *sg_arr; | ||
147 | |||
148 | void (*tasklet_complete)(struct asd_ascb *, struct done_list_struct *); | ||
149 | u8 uldd_timer:1; | ||
150 | |||
151 | /* internally generated command */ | ||
152 | struct timer_list timer; | ||
153 | struct completion completion; | ||
154 | u8 tag_valid:1; | ||
155 | __be16 tag; /* error recovery only */ | ||
156 | |||
157 | /* If this is an Empty SCB, index of first edb in seq->edb_arr. */ | ||
158 | int edb_index; | ||
159 | |||
160 | /* Used by the timer timeout function. */ | ||
161 | int tc_index; | ||
162 | |||
163 | void *uldd_task; | ||
164 | }; | ||
165 | |||
166 | #define ASD_DL_SIZE_BITS 0x8 | ||
167 | #define ASD_DL_SIZE (1<<(2+ASD_DL_SIZE_BITS)) | ||
168 | #define ASD_DEF_DL_TOGGLE 0x01 | ||
169 | |||
170 | struct asd_seq_data { | ||
171 | spinlock_t pend_q_lock; | ||
172 | u16 scbpro; | ||
173 | int pending; | ||
174 | struct list_head pend_q; | ||
175 | int can_queue; /* per adapter */ | ||
176 | struct asd_dma_tok next_scb; /* next scb to be delivered to CSEQ */ | ||
177 | |||
178 | spinlock_t tc_index_lock; | ||
179 | void **tc_index_array; | ||
180 | void *tc_index_bitmap; | ||
181 | int tc_index_bitmap_bits; | ||
182 | |||
183 | struct tasklet_struct dl_tasklet; | ||
184 | struct done_list_struct *dl; /* array of done list entries, equals */ | ||
185 | struct asd_dma_tok *actual_dl; /* actual_dl->vaddr */ | ||
186 | int dl_toggle; | ||
187 | int dl_next; | ||
188 | |||
189 | int num_edbs; | ||
190 | struct asd_dma_tok **edb_arr; | ||
191 | int num_escbs; | ||
192 | struct asd_ascb **escb_arr; /* array of pointers to escbs */ | ||
193 | }; | ||
194 | |||
195 | /* This is the Host Adapter structure. It describes the hardware | ||
196 | * SAS adapter. | ||
197 | */ | ||
198 | struct asd_ha_struct { | ||
199 | struct pci_dev *pcidev; | ||
200 | const char *name; | ||
201 | |||
202 | struct sas_ha_struct sas_ha; | ||
203 | |||
204 | u8 revision_id; | ||
205 | |||
206 | int iospace; | ||
207 | spinlock_t iolock; | ||
208 | struct asd_ha_addrspace io_handle[2]; | ||
209 | |||
210 | struct hw_profile hw_prof; | ||
211 | |||
212 | struct asd_phy phys[ASD_MAX_PHYS]; | ||
213 | struct asd_sas_port ports[ASD_MAX_PHYS]; | ||
214 | |||
215 | struct dma_pool *scb_pool; | ||
216 | |||
217 | struct asd_seq_data seq; /* sequencer related */ | ||
218 | }; | ||
219 | |||
220 | /* ---------- Common macros ---------- */ | ||
221 | |||
222 | #define ASD_BUSADDR_LO(__dma_handle) ((u32)(__dma_handle)) | ||
223 | #define ASD_BUSADDR_HI(__dma_handle) (((sizeof(dma_addr_t))==8) \ | ||
224 | ? ((u32)((__dma_handle) >> 32)) \ | ||
225 | : ((u32)0)) | ||
226 | |||
227 | #define dev_to_asd_ha(__dev) pci_get_drvdata(to_pci_dev(__dev)) | ||
228 | #define SCB_SITE_VALID(__site_no) (((__site_no) & 0xF0FF) != 0x00FF \ | ||
229 | && ((__site_no) & 0xF0FF) > 0x001F) | ||
230 | /* For each bit set in __lseq_mask, set __lseq to equal the bit | ||
231 | * position of the set bit and execute the statement following. | ||
232 | * __mc is the temporary mask, used as a mask "counter". | ||
233 | */ | ||
234 | #define for_each_sequencer(__lseq_mask, __mc, __lseq) \ | ||
235 | for ((__mc)=(__lseq_mask),(__lseq)=0;(__mc)!=0;(__lseq++),(__mc)>>=1)\ | ||
236 | if (((__mc) & 1)) | ||
237 | #define for_each_phy(__lseq_mask, __mc, __lseq) \ | ||
238 | for ((__mc)=(__lseq_mask),(__lseq)=0;(__mc)!=0;(__lseq++),(__mc)>>=1)\ | ||
239 | if (((__mc) & 1)) | ||
240 | |||
241 | #define PHY_ENABLED(_HA, _I) ((_HA)->hw_prof.enabled_phys & (1<<(_I))) | ||
242 | |||
243 | /* ---------- DMA allocs ---------- */ | ||
244 | |||
245 | static inline struct asd_dma_tok *asd_dmatok_alloc(unsigned int flags) | ||
246 | { | ||
247 | return kmem_cache_alloc(asd_dma_token_cache, flags); | ||
248 | } | ||
249 | |||
250 | static inline void asd_dmatok_free(struct asd_dma_tok *token) | ||
251 | { | ||
252 | kmem_cache_free(asd_dma_token_cache, token); | ||
253 | } | ||
254 | |||
255 | static inline struct asd_dma_tok *asd_alloc_coherent(struct asd_ha_struct * | ||
256 | asd_ha, size_t size, | ||
257 | unsigned int flags) | ||
258 | { | ||
259 | struct asd_dma_tok *token = asd_dmatok_alloc(flags); | ||
260 | if (token) { | ||
261 | token->size = size; | ||
262 | token->vaddr = dma_alloc_coherent(&asd_ha->pcidev->dev, | ||
263 | token->size, | ||
264 | &token->dma_handle, | ||
265 | flags); | ||
266 | if (!token->vaddr) { | ||
267 | asd_dmatok_free(token); | ||
268 | token = NULL; | ||
269 | } | ||
270 | } | ||
271 | return token; | ||
272 | } | ||
273 | |||
274 | static inline void asd_free_coherent(struct asd_ha_struct *asd_ha, | ||
275 | struct asd_dma_tok *token) | ||
276 | { | ||
277 | if (token) { | ||
278 | dma_free_coherent(&asd_ha->pcidev->dev, token->size, | ||
279 | token->vaddr, token->dma_handle); | ||
280 | asd_dmatok_free(token); | ||
281 | } | ||
282 | } | ||
283 | |||
284 | static inline void asd_init_ascb(struct asd_ha_struct *asd_ha, | ||
285 | struct asd_ascb *ascb) | ||
286 | { | ||
287 | INIT_LIST_HEAD(&ascb->list); | ||
288 | ascb->scb = ascb->dma_scb.vaddr; | ||
289 | ascb->ha = asd_ha; | ||
290 | ascb->timer.function = NULL; | ||
291 | init_timer(&ascb->timer); | ||
292 | ascb->tc_index = -1; | ||
293 | init_completion(&ascb->completion); | ||
294 | } | ||
295 | |||
296 | /* Must be called with the tc_index_lock held! | ||
297 | */ | ||
298 | static inline void asd_tc_index_release(struct asd_seq_data *seq, int index) | ||
299 | { | ||
300 | seq->tc_index_array[index] = NULL; | ||
301 | clear_bit(index, seq->tc_index_bitmap); | ||
302 | } | ||
303 | |||
304 | /* Must be called with the tc_index_lock held! | ||
305 | */ | ||
306 | static inline int asd_tc_index_get(struct asd_seq_data *seq, void *ptr) | ||
307 | { | ||
308 | int index; | ||
309 | |||
310 | index = find_first_zero_bit(seq->tc_index_bitmap, | ||
311 | seq->tc_index_bitmap_bits); | ||
312 | if (index == seq->tc_index_bitmap_bits) | ||
313 | return -1; | ||
314 | |||
315 | seq->tc_index_array[index] = ptr; | ||
316 | set_bit(index, seq->tc_index_bitmap); | ||
317 | |||
318 | return index; | ||
319 | } | ||
320 | |||
321 | /* Must be called with the tc_index_lock held! | ||
322 | */ | ||
323 | static inline void *asd_tc_index_find(struct asd_seq_data *seq, int index) | ||
324 | { | ||
325 | return seq->tc_index_array[index]; | ||
326 | } | ||
327 | |||
328 | /** | ||
329 | * asd_ascb_free -- free a single aSCB after is has completed | ||
330 | * @ascb: pointer to the aSCB of interest | ||
331 | * | ||
332 | * This frees an aSCB after it has been executed/completed by | ||
333 | * the sequencer. | ||
334 | */ | ||
335 | static inline void asd_ascb_free(struct asd_ascb *ascb) | ||
336 | { | ||
337 | if (ascb) { | ||
338 | struct asd_ha_struct *asd_ha = ascb->ha; | ||
339 | unsigned long flags; | ||
340 | |||
341 | BUG_ON(!list_empty(&ascb->list)); | ||
342 | spin_lock_irqsave(&ascb->ha->seq.tc_index_lock, flags); | ||
343 | asd_tc_index_release(&ascb->ha->seq, ascb->tc_index); | ||
344 | spin_unlock_irqrestore(&ascb->ha->seq.tc_index_lock, flags); | ||
345 | dma_pool_free(asd_ha->scb_pool, ascb->dma_scb.vaddr, | ||
346 | ascb->dma_scb.dma_handle); | ||
347 | kmem_cache_free(asd_ascb_cache, ascb); | ||
348 | } | ||
349 | } | ||
350 | |||
351 | /** | ||
352 | * asd_ascb_list_free -- free a list of ascbs | ||
353 | * @ascb_list: a list of ascbs | ||
354 | * | ||
355 | * This function will free a list of ascbs allocated by asd_ascb_alloc_list. | ||
356 | * It is used when say the scb queueing function returned QUEUE_FULL, | ||
357 | * and we do not need the ascbs any more. | ||
358 | */ | ||
359 | static inline void asd_ascb_free_list(struct asd_ascb *ascb_list) | ||
360 | { | ||
361 | LIST_HEAD(list); | ||
362 | struct list_head *n, *pos; | ||
363 | |||
364 | __list_add(&list, ascb_list->list.prev, &ascb_list->list); | ||
365 | list_for_each_safe(pos, n, &list) { | ||
366 | list_del_init(pos); | ||
367 | asd_ascb_free(list_entry(pos, struct asd_ascb, list)); | ||
368 | } | ||
369 | } | ||
370 | |||
371 | /* ---------- Function declarations ---------- */ | ||
372 | |||
373 | int asd_init_hw(struct asd_ha_struct *asd_ha); | ||
374 | irqreturn_t asd_hw_isr(int irq, void *dev_id, struct pt_regs *regs); | ||
375 | |||
376 | |||
377 | struct asd_ascb *asd_ascb_alloc_list(struct asd_ha_struct | ||
378 | *asd_ha, int *num, | ||
379 | unsigned int gfp_mask); | ||
380 | |||
381 | int asd_post_ascb_list(struct asd_ha_struct *asd_ha, struct asd_ascb *ascb, | ||
382 | int num); | ||
383 | int asd_post_escb_list(struct asd_ha_struct *asd_ha, struct asd_ascb *ascb, | ||
384 | int num); | ||
385 | |||
386 | int asd_init_post_escbs(struct asd_ha_struct *asd_ha); | ||
387 | void asd_build_control_phy(struct asd_ascb *ascb, int phy_id, u8 subfunc); | ||
388 | void asd_control_led(struct asd_ha_struct *asd_ha, int phy_id, int op); | ||
389 | void asd_turn_led(struct asd_ha_struct *asd_ha, int phy_id, int op); | ||
390 | int asd_enable_phys(struct asd_ha_struct *asd_ha, const u8 phy_mask); | ||
391 | void asd_build_initiate_link_adm_task(struct asd_ascb *ascb, int phy_id, | ||
392 | u8 subfunc); | ||
393 | |||
394 | void asd_ascb_timedout(unsigned long data); | ||
395 | int asd_chip_hardrst(struct asd_ha_struct *asd_ha); | ||
396 | |||
397 | #endif | ||
diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c new file mode 100644 index 000000000000..3ec2e46f80c6 --- /dev/null +++ b/drivers/scsi/aic94xx/aic94xx_init.c | |||
@@ -0,0 +1,860 @@ | |||
1 | /* | ||
2 | * Aic94xx SAS/SATA driver initialization. | ||
3 | * | ||
4 | * Copyright (C) 2005 Adaptec, Inc. All rights reserved. | ||
5 | * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> | ||
6 | * | ||
7 | * This file is licensed under GPLv2. | ||
8 | * | ||
9 | * This file is part of the aic94xx driver. | ||
10 | * | ||
11 | * The aic94xx driver is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License as | ||
13 | * published by the Free Software Foundation; version 2 of the | ||
14 | * License. | ||
15 | * | ||
16 | * The aic94xx driver is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
19 | * General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with the aic94xx driver; if not, write to the Free Software | ||
23 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #include <linux/config.h> | ||
28 | #include <linux/module.h> | ||
29 | #include <linux/init.h> | ||
30 | #include <linux/kernel.h> | ||
31 | #include <linux/pci.h> | ||
32 | #include <linux/delay.h> | ||
33 | |||
34 | #include <scsi/scsi_host.h> | ||
35 | |||
36 | #include "aic94xx.h" | ||
37 | #include "aic94xx_reg.h" | ||
38 | #include "aic94xx_hwi.h" | ||
39 | #include "aic94xx_seq.h" | ||
40 | |||
41 | /* The format is "version.release.patchlevel" */ | ||
42 | #define ASD_DRIVER_VERSION "1.0.2" | ||
43 | |||
44 | static int use_msi = 0; | ||
45 | module_param_named(use_msi, use_msi, int, S_IRUGO); | ||
46 | MODULE_PARM_DESC(use_msi, "\n" | ||
47 | "\tEnable(1) or disable(0) using PCI MSI.\n" | ||
48 | "\tDefault: 0"); | ||
49 | |||
50 | static int lldd_max_execute_num = 0; | ||
51 | module_param_named(collector, lldd_max_execute_num, int, S_IRUGO); | ||
52 | MODULE_PARM_DESC(collector, "\n" | ||
53 | "\tIf greater than one, tells the SAS Layer to run in Task Collector\n" | ||
54 | "\tMode. If 1 or 0, tells the SAS Layer to run in Direct Mode.\n" | ||
55 | "\tThe aic94xx SAS LLDD supports both modes.\n" | ||
56 | "\tDefault: 0 (Direct Mode).\n"); | ||
57 | |||
58 | char sas_addr_str[2*SAS_ADDR_SIZE + 1] = ""; | ||
59 | |||
60 | static struct scsi_transport_template *aic94xx_transport_template; | ||
61 | |||
62 | static struct scsi_host_template aic94xx_sht = { | ||
63 | .module = THIS_MODULE, | ||
64 | /* .name is initialized */ | ||
65 | .name = "aic94xx", | ||
66 | .queuecommand = sas_queuecommand, | ||
67 | .target_alloc = sas_target_alloc, | ||
68 | .slave_configure = sas_slave_configure, | ||
69 | .slave_destroy = sas_slave_destroy, | ||
70 | .change_queue_depth = sas_change_queue_depth, | ||
71 | .change_queue_type = sas_change_queue_type, | ||
72 | .bios_param = sas_bios_param, | ||
73 | .can_queue = 1, | ||
74 | .cmd_per_lun = 1, | ||
75 | .this_id = -1, | ||
76 | .sg_tablesize = SG_ALL, | ||
77 | .max_sectors = SCSI_DEFAULT_MAX_SECTORS, | ||
78 | .use_clustering = ENABLE_CLUSTERING, | ||
79 | }; | ||
80 | |||
81 | static int __devinit asd_map_memio(struct asd_ha_struct *asd_ha) | ||
82 | { | ||
83 | int err, i; | ||
84 | struct asd_ha_addrspace *io_handle; | ||
85 | |||
86 | asd_ha->iospace = 0; | ||
87 | for (i = 0; i < 3; i += 2) { | ||
88 | io_handle = &asd_ha->io_handle[i==0?0:1]; | ||
89 | io_handle->start = pci_resource_start(asd_ha->pcidev, i); | ||
90 | io_handle->len = pci_resource_len(asd_ha->pcidev, i); | ||
91 | io_handle->flags = pci_resource_flags(asd_ha->pcidev, i); | ||
92 | err = -ENODEV; | ||
93 | if (!io_handle->start || !io_handle->len) { | ||
94 | asd_printk("MBAR%d start or length for %s is 0.\n", | ||
95 | i==0?0:1, pci_name(asd_ha->pcidev)); | ||
96 | goto Err; | ||
97 | } | ||
98 | err = pci_request_region(asd_ha->pcidev, i, ASD_DRIVER_NAME); | ||
99 | if (err) { | ||
100 | asd_printk("couldn't reserve memory region for %s\n", | ||
101 | pci_name(asd_ha->pcidev)); | ||
102 | goto Err; | ||
103 | } | ||
104 | if (io_handle->flags & IORESOURCE_CACHEABLE) | ||
105 | io_handle->addr = ioremap(io_handle->start, | ||
106 | io_handle->len); | ||
107 | else | ||
108 | io_handle->addr = ioremap_nocache(io_handle->start, | ||
109 | io_handle->len); | ||
110 | if (!io_handle->addr) { | ||
111 | asd_printk("couldn't map MBAR%d of %s\n", i==0?0:1, | ||
112 | pci_name(asd_ha->pcidev)); | ||
113 | goto Err_unreq; | ||
114 | } | ||
115 | } | ||
116 | |||
117 | return 0; | ||
118 | Err_unreq: | ||
119 | pci_release_region(asd_ha->pcidev, i); | ||
120 | Err: | ||
121 | if (i > 0) { | ||
122 | io_handle = &asd_ha->io_handle[0]; | ||
123 | iounmap(io_handle->addr); | ||
124 | pci_release_region(asd_ha->pcidev, 0); | ||
125 | } | ||
126 | return err; | ||
127 | } | ||
128 | |||
129 | static void __devexit asd_unmap_memio(struct asd_ha_struct *asd_ha) | ||
130 | { | ||
131 | struct asd_ha_addrspace *io_handle; | ||
132 | |||
133 | io_handle = &asd_ha->io_handle[1]; | ||
134 | iounmap(io_handle->addr); | ||
135 | pci_release_region(asd_ha->pcidev, 2); | ||
136 | |||
137 | io_handle = &asd_ha->io_handle[0]; | ||
138 | iounmap(io_handle->addr); | ||
139 | pci_release_region(asd_ha->pcidev, 0); | ||
140 | } | ||
141 | |||
142 | static int __devinit asd_map_ioport(struct asd_ha_struct *asd_ha) | ||
143 | { | ||
144 | int i = PCI_IOBAR_OFFSET, err; | ||
145 | struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0]; | ||
146 | |||
147 | asd_ha->iospace = 1; | ||
148 | io_handle->start = pci_resource_start(asd_ha->pcidev, i); | ||
149 | io_handle->len = pci_resource_len(asd_ha->pcidev, i); | ||
150 | io_handle->flags = pci_resource_flags(asd_ha->pcidev, i); | ||
151 | io_handle->addr = (void __iomem *) io_handle->start; | ||
152 | if (!io_handle->start || !io_handle->len) { | ||
153 | asd_printk("couldn't get IO ports for %s\n", | ||
154 | pci_name(asd_ha->pcidev)); | ||
155 | return -ENODEV; | ||
156 | } | ||
157 | err = pci_request_region(asd_ha->pcidev, i, ASD_DRIVER_NAME); | ||
158 | if (err) { | ||
159 | asd_printk("couldn't reserve io space for %s\n", | ||
160 | pci_name(asd_ha->pcidev)); | ||
161 | } | ||
162 | |||
163 | return err; | ||
164 | } | ||
165 | |||
166 | static void __devexit asd_unmap_ioport(struct asd_ha_struct *asd_ha) | ||
167 | { | ||
168 | pci_release_region(asd_ha->pcidev, PCI_IOBAR_OFFSET); | ||
169 | } | ||
170 | |||
171 | static int __devinit asd_map_ha(struct asd_ha_struct *asd_ha) | ||
172 | { | ||
173 | int err; | ||
174 | u16 cmd_reg; | ||
175 | |||
176 | err = pci_read_config_word(asd_ha->pcidev, PCI_COMMAND, &cmd_reg); | ||
177 | if (err) { | ||
178 | asd_printk("couldn't read command register of %s\n", | ||
179 | pci_name(asd_ha->pcidev)); | ||
180 | goto Err; | ||
181 | } | ||
182 | |||
183 | err = -ENODEV; | ||
184 | if (cmd_reg & PCI_COMMAND_MEMORY) { | ||
185 | if ((err = asd_map_memio(asd_ha))) | ||
186 | goto Err; | ||
187 | } else if (cmd_reg & PCI_COMMAND_IO) { | ||
188 | if ((err = asd_map_ioport(asd_ha))) | ||
189 | goto Err; | ||
190 | asd_printk("%s ioport mapped -- upgrade your hardware\n", | ||
191 | pci_name(asd_ha->pcidev)); | ||
192 | } else { | ||
193 | asd_printk("no proper device access to %s\n", | ||
194 | pci_name(asd_ha->pcidev)); | ||
195 | goto Err; | ||
196 | } | ||
197 | |||
198 | return 0; | ||
199 | Err: | ||
200 | return err; | ||
201 | } | ||
202 | |||
203 | static void __devexit asd_unmap_ha(struct asd_ha_struct *asd_ha) | ||
204 | { | ||
205 | if (asd_ha->iospace) | ||
206 | asd_unmap_ioport(asd_ha); | ||
207 | else | ||
208 | asd_unmap_memio(asd_ha); | ||
209 | } | ||
210 | |||
211 | static const char *asd_dev_rev[30] = { | ||
212 | [0] = "A0", | ||
213 | [1] = "A1", | ||
214 | [8] = "B0", | ||
215 | }; | ||
216 | |||
217 | static int __devinit asd_common_setup(struct asd_ha_struct *asd_ha) | ||
218 | { | ||
219 | int err, i; | ||
220 | |||
221 | err = pci_read_config_byte(asd_ha->pcidev, PCI_REVISION_ID, | ||
222 | &asd_ha->revision_id); | ||
223 | if (err) { | ||
224 | asd_printk("couldn't read REVISION ID register of %s\n", | ||
225 | pci_name(asd_ha->pcidev)); | ||
226 | goto Err; | ||
227 | } | ||
228 | err = -ENODEV; | ||
229 | if (asd_ha->revision_id < AIC9410_DEV_REV_B0) { | ||
230 | asd_printk("%s is revision %s (%X), which is not supported\n", | ||
231 | pci_name(asd_ha->pcidev), | ||
232 | asd_dev_rev[asd_ha->revision_id], | ||
233 | asd_ha->revision_id); | ||
234 | goto Err; | ||
235 | } | ||
236 | /* Provide some sane default values. */ | ||
237 | asd_ha->hw_prof.max_scbs = 512; | ||
238 | asd_ha->hw_prof.max_ddbs = 128; | ||
239 | asd_ha->hw_prof.num_phys = ASD_MAX_PHYS; | ||
240 | /* All phys are enabled, by default. */ | ||
241 | asd_ha->hw_prof.enabled_phys = 0xFF; | ||
242 | for (i = 0; i < ASD_MAX_PHYS; i++) { | ||
243 | asd_ha->hw_prof.phy_desc[i].max_sas_lrate = PHY_LINKRATE_3; | ||
244 | asd_ha->hw_prof.phy_desc[i].min_sas_lrate = PHY_LINKRATE_1_5; | ||
245 | asd_ha->hw_prof.phy_desc[i].max_sata_lrate= PHY_LINKRATE_1_5; | ||
246 | asd_ha->hw_prof.phy_desc[i].min_sata_lrate= PHY_LINKRATE_1_5; | ||
247 | } | ||
248 | |||
249 | return 0; | ||
250 | Err: | ||
251 | return err; | ||
252 | } | ||
253 | |||
254 | static int __devinit asd_aic9410_setup(struct asd_ha_struct *asd_ha) | ||
255 | { | ||
256 | int err = asd_common_setup(asd_ha); | ||
257 | |||
258 | if (err) | ||
259 | return err; | ||
260 | |||
261 | asd_ha->hw_prof.addr_range = 8; | ||
262 | asd_ha->hw_prof.port_name_base = 0; | ||
263 | asd_ha->hw_prof.dev_name_base = 8; | ||
264 | asd_ha->hw_prof.sata_name_base = 16; | ||
265 | |||
266 | return 0; | ||
267 | } | ||
268 | |||
269 | static int __devinit asd_aic9405_setup(struct asd_ha_struct *asd_ha) | ||
270 | { | ||
271 | int err = asd_common_setup(asd_ha); | ||
272 | |||
273 | if (err) | ||
274 | return err; | ||
275 | |||
276 | asd_ha->hw_prof.addr_range = 4; | ||
277 | asd_ha->hw_prof.port_name_base = 0; | ||
278 | asd_ha->hw_prof.dev_name_base = 4; | ||
279 | asd_ha->hw_prof.sata_name_base = 8; | ||
280 | |||
281 | return 0; | ||
282 | } | ||
283 | |||
284 | static ssize_t asd_show_dev_rev(struct device *dev, | ||
285 | struct device_attribute *attr, char *buf) | ||
286 | { | ||
287 | struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev); | ||
288 | return snprintf(buf, PAGE_SIZE, "%s\n", | ||
289 | asd_dev_rev[asd_ha->revision_id]); | ||
290 | } | ||
291 | static DEVICE_ATTR(revision, S_IRUGO, asd_show_dev_rev, NULL); | ||
292 | |||
293 | static ssize_t asd_show_dev_bios_build(struct device *dev, | ||
294 | struct device_attribute *attr,char *buf) | ||
295 | { | ||
296 | struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev); | ||
297 | return snprintf(buf, PAGE_SIZE, "%d\n", asd_ha->hw_prof.bios.bld); | ||
298 | } | ||
299 | static DEVICE_ATTR(bios_build, S_IRUGO, asd_show_dev_bios_build, NULL); | ||
300 | |||
301 | static ssize_t asd_show_dev_pcba_sn(struct device *dev, | ||
302 | struct device_attribute *attr, char *buf) | ||
303 | { | ||
304 | struct asd_ha_struct *asd_ha = dev_to_asd_ha(dev); | ||
305 | return snprintf(buf, PAGE_SIZE, "%s\n", asd_ha->hw_prof.pcba_sn); | ||
306 | } | ||
307 | static DEVICE_ATTR(pcba_sn, S_IRUGO, asd_show_dev_pcba_sn, NULL); | ||
308 | |||
309 | static void asd_create_dev_attrs(struct asd_ha_struct *asd_ha) | ||
310 | { | ||
311 | device_create_file(&asd_ha->pcidev->dev, &dev_attr_revision); | ||
312 | device_create_file(&asd_ha->pcidev->dev, &dev_attr_bios_build); | ||
313 | device_create_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn); | ||
314 | } | ||
315 | |||
316 | static void asd_remove_dev_attrs(struct asd_ha_struct *asd_ha) | ||
317 | { | ||
318 | device_remove_file(&asd_ha->pcidev->dev, &dev_attr_revision); | ||
319 | device_remove_file(&asd_ha->pcidev->dev, &dev_attr_bios_build); | ||
320 | device_remove_file(&asd_ha->pcidev->dev, &dev_attr_pcba_sn); | ||
321 | } | ||
322 | |||
323 | /* The first entry, 0, is used for dynamic ids, the rest for devices | ||
324 | * we know about. | ||
325 | */ | ||
326 | static struct asd_pcidev_struct { | ||
327 | const char * name; | ||
328 | int (*setup)(struct asd_ha_struct *asd_ha); | ||
329 | } asd_pcidev_data[] = { | ||
330 | /* Id 0 is used for dynamic ids. */ | ||
331 | { .name = "Adaptec AIC-94xx SAS/SATA Host Adapter", | ||
332 | .setup = asd_aic9410_setup | ||
333 | }, | ||
334 | { .name = "Adaptec AIC-9410W SAS/SATA Host Adapter", | ||
335 | .setup = asd_aic9410_setup | ||
336 | }, | ||
337 | { .name = "Adaptec AIC-9405W SAS/SATA Host Adapter", | ||
338 | .setup = asd_aic9405_setup | ||
339 | }, | ||
340 | }; | ||
341 | |||
342 | static inline int asd_create_ha_caches(struct asd_ha_struct *asd_ha) | ||
343 | { | ||
344 | asd_ha->scb_pool = dma_pool_create(ASD_DRIVER_NAME "_scb_pool", | ||
345 | &asd_ha->pcidev->dev, | ||
346 | sizeof(struct scb), | ||
347 | 8, 0); | ||
348 | if (!asd_ha->scb_pool) { | ||
349 | asd_printk("couldn't create scb pool\n"); | ||
350 | return -ENOMEM; | ||
351 | } | ||
352 | |||
353 | return 0; | ||
354 | } | ||
355 | |||
356 | /** | ||
357 | * asd_free_edbs -- free empty data buffers | ||
358 | * asd_ha: pointer to host adapter structure | ||
359 | */ | ||
360 | static inline void asd_free_edbs(struct asd_ha_struct *asd_ha) | ||
361 | { | ||
362 | struct asd_seq_data *seq = &asd_ha->seq; | ||
363 | int i; | ||
364 | |||
365 | for (i = 0; i < seq->num_edbs; i++) | ||
366 | asd_free_coherent(asd_ha, seq->edb_arr[i]); | ||
367 | kfree(seq->edb_arr); | ||
368 | seq->edb_arr = NULL; | ||
369 | } | ||
370 | |||
371 | static inline void asd_free_escbs(struct asd_ha_struct *asd_ha) | ||
372 | { | ||
373 | struct asd_seq_data *seq = &asd_ha->seq; | ||
374 | int i; | ||
375 | |||
376 | for (i = 0; i < seq->num_escbs; i++) { | ||
377 | if (!list_empty(&seq->escb_arr[i]->list)) | ||
378 | list_del_init(&seq->escb_arr[i]->list); | ||
379 | |||
380 | asd_ascb_free(seq->escb_arr[i]); | ||
381 | } | ||
382 | kfree(seq->escb_arr); | ||
383 | seq->escb_arr = NULL; | ||
384 | } | ||
385 | |||
386 | static inline void asd_destroy_ha_caches(struct asd_ha_struct *asd_ha) | ||
387 | { | ||
388 | int i; | ||
389 | |||
390 | if (asd_ha->hw_prof.ddb_ext) | ||
391 | asd_free_coherent(asd_ha, asd_ha->hw_prof.ddb_ext); | ||
392 | if (asd_ha->hw_prof.scb_ext) | ||
393 | asd_free_coherent(asd_ha, asd_ha->hw_prof.scb_ext); | ||
394 | |||
395 | if (asd_ha->hw_prof.ddb_bitmap) | ||
396 | kfree(asd_ha->hw_prof.ddb_bitmap); | ||
397 | asd_ha->hw_prof.ddb_bitmap = NULL; | ||
398 | |||
399 | for (i = 0; i < ASD_MAX_PHYS; i++) { | ||
400 | struct asd_phy *phy = &asd_ha->phys[i]; | ||
401 | |||
402 | asd_free_coherent(asd_ha, phy->id_frm_tok); | ||
403 | } | ||
404 | if (asd_ha->seq.escb_arr) | ||
405 | asd_free_escbs(asd_ha); | ||
406 | if (asd_ha->seq.edb_arr) | ||
407 | asd_free_edbs(asd_ha); | ||
408 | if (asd_ha->hw_prof.ue.area) { | ||
409 | kfree(asd_ha->hw_prof.ue.area); | ||
410 | asd_ha->hw_prof.ue.area = NULL; | ||
411 | } | ||
412 | if (asd_ha->seq.tc_index_array) { | ||
413 | kfree(asd_ha->seq.tc_index_array); | ||
414 | kfree(asd_ha->seq.tc_index_bitmap); | ||
415 | asd_ha->seq.tc_index_array = NULL; | ||
416 | asd_ha->seq.tc_index_bitmap = NULL; | ||
417 | } | ||
418 | if (asd_ha->seq.actual_dl) { | ||
419 | asd_free_coherent(asd_ha, asd_ha->seq.actual_dl); | ||
420 | asd_ha->seq.actual_dl = NULL; | ||
421 | asd_ha->seq.dl = NULL; | ||
422 | } | ||
423 | if (asd_ha->seq.next_scb.vaddr) { | ||
424 | dma_pool_free(asd_ha->scb_pool, asd_ha->seq.next_scb.vaddr, | ||
425 | asd_ha->seq.next_scb.dma_handle); | ||
426 | asd_ha->seq.next_scb.vaddr = NULL; | ||
427 | } | ||
428 | dma_pool_destroy(asd_ha->scb_pool); | ||
429 | asd_ha->scb_pool = NULL; | ||
430 | } | ||
431 | |||
432 | kmem_cache_t *asd_dma_token_cache; | ||
433 | kmem_cache_t *asd_ascb_cache; | ||
434 | |||
435 | static int asd_create_global_caches(void) | ||
436 | { | ||
437 | if (!asd_dma_token_cache) { | ||
438 | asd_dma_token_cache | ||
439 | = kmem_cache_create(ASD_DRIVER_NAME "_dma_token", | ||
440 | sizeof(struct asd_dma_tok), | ||
441 | 0, | ||
442 | SLAB_HWCACHE_ALIGN, | ||
443 | NULL, NULL); | ||
444 | if (!asd_dma_token_cache) { | ||
445 | asd_printk("couldn't create dma token cache\n"); | ||
446 | return -ENOMEM; | ||
447 | } | ||
448 | } | ||
449 | |||
450 | if (!asd_ascb_cache) { | ||
451 | asd_ascb_cache = kmem_cache_create(ASD_DRIVER_NAME "_ascb", | ||
452 | sizeof(struct asd_ascb), | ||
453 | 0, | ||
454 | SLAB_HWCACHE_ALIGN, | ||
455 | NULL, NULL); | ||
456 | if (!asd_ascb_cache) { | ||
457 | asd_printk("couldn't create ascb cache\n"); | ||
458 | goto Err; | ||
459 | } | ||
460 | } | ||
461 | |||
462 | return 0; | ||
463 | Err: | ||
464 | kmem_cache_destroy(asd_dma_token_cache); | ||
465 | asd_dma_token_cache = NULL; | ||
466 | return -ENOMEM; | ||
467 | } | ||
468 | |||
469 | static void asd_destroy_global_caches(void) | ||
470 | { | ||
471 | if (asd_dma_token_cache) | ||
472 | kmem_cache_destroy(asd_dma_token_cache); | ||
473 | asd_dma_token_cache = NULL; | ||
474 | |||
475 | if (asd_ascb_cache) | ||
476 | kmem_cache_destroy(asd_ascb_cache); | ||
477 | asd_ascb_cache = NULL; | ||
478 | } | ||
479 | |||
480 | static int asd_register_sas_ha(struct asd_ha_struct *asd_ha) | ||
481 | { | ||
482 | int i; | ||
483 | struct asd_sas_phy **sas_phys = | ||
484 | kmalloc(ASD_MAX_PHYS * sizeof(struct asd_sas_phy), GFP_KERNEL); | ||
485 | struct asd_sas_port **sas_ports = | ||
486 | kmalloc(ASD_MAX_PHYS * sizeof(struct asd_sas_port), GFP_KERNEL); | ||
487 | |||
488 | if (!sas_phys || !sas_ports) { | ||
489 | kfree(sas_phys); | ||
490 | kfree(sas_ports); | ||
491 | return -ENOMEM; | ||
492 | } | ||
493 | |||
494 | asd_ha->sas_ha.sas_ha_name = (char *) asd_ha->name; | ||
495 | asd_ha->sas_ha.lldd_module = THIS_MODULE; | ||
496 | asd_ha->sas_ha.sas_addr = &asd_ha->hw_prof.sas_addr[0]; | ||
497 | |||
498 | for (i = 0; i < ASD_MAX_PHYS; i++) { | ||
499 | sas_phys[i] = &asd_ha->phys[i].sas_phy; | ||
500 | sas_ports[i] = &asd_ha->ports[i]; | ||
501 | } | ||
502 | |||
503 | asd_ha->sas_ha.sas_phy = sas_phys; | ||
504 | asd_ha->sas_ha.sas_port= sas_ports; | ||
505 | asd_ha->sas_ha.num_phys= ASD_MAX_PHYS; | ||
506 | |||
507 | asd_ha->sas_ha.lldd_queue_size = asd_ha->seq.can_queue; | ||
508 | |||
509 | return sas_register_ha(&asd_ha->sas_ha); | ||
510 | } | ||
511 | |||
512 | static int asd_unregister_sas_ha(struct asd_ha_struct *asd_ha) | ||
513 | { | ||
514 | int err; | ||
515 | |||
516 | err = sas_unregister_ha(&asd_ha->sas_ha); | ||
517 | |||
518 | sas_remove_host(asd_ha->sas_ha.core.shost); | ||
519 | scsi_remove_host(asd_ha->sas_ha.core.shost); | ||
520 | scsi_host_put(asd_ha->sas_ha.core.shost); | ||
521 | |||
522 | kfree(asd_ha->sas_ha.sas_phy); | ||
523 | kfree(asd_ha->sas_ha.sas_port); | ||
524 | |||
525 | return err; | ||
526 | } | ||
527 | |||
528 | static int __devinit asd_pci_probe(struct pci_dev *dev, | ||
529 | const struct pci_device_id *id) | ||
530 | { | ||
531 | struct asd_pcidev_struct *asd_dev; | ||
532 | unsigned asd_id = (unsigned) id->driver_data; | ||
533 | struct asd_ha_struct *asd_ha; | ||
534 | struct Scsi_Host *shost; | ||
535 | int err; | ||
536 | |||
537 | if (asd_id >= ARRAY_SIZE(asd_pcidev_data)) { | ||
538 | asd_printk("wrong driver_data in PCI table\n"); | ||
539 | return -ENODEV; | ||
540 | } | ||
541 | |||
542 | if ((err = pci_enable_device(dev))) { | ||
543 | asd_printk("couldn't enable device %s\n", pci_name(dev)); | ||
544 | return err; | ||
545 | } | ||
546 | |||
547 | pci_set_master(dev); | ||
548 | |||
549 | err = -ENOMEM; | ||
550 | |||
551 | shost = scsi_host_alloc(&aic94xx_sht, sizeof(void *)); | ||
552 | if (!shost) | ||
553 | goto Err; | ||
554 | |||
555 | asd_dev = &asd_pcidev_data[asd_id]; | ||
556 | |||
557 | asd_ha = kzalloc(sizeof(*asd_ha), GFP_KERNEL); | ||
558 | if (!asd_ha) { | ||
559 | asd_printk("out of memory\n"); | ||
560 | goto Err; | ||
561 | } | ||
562 | asd_ha->pcidev = dev; | ||
563 | asd_ha->sas_ha.pcidev = asd_ha->pcidev; | ||
564 | asd_ha->sas_ha.lldd_ha = asd_ha; | ||
565 | |||
566 | asd_ha->name = asd_dev->name; | ||
567 | asd_printk("found %s, device %s\n", asd_ha->name, pci_name(dev)); | ||
568 | |||
569 | SHOST_TO_SAS_HA(shost) = &asd_ha->sas_ha; | ||
570 | asd_ha->sas_ha.core.shost = shost; | ||
571 | shost->transportt = aic94xx_transport_template; | ||
572 | shost->max_id = ~0; | ||
573 | shost->max_lun = ~0; | ||
574 | shost->max_cmd_len = 16; | ||
575 | |||
576 | err = scsi_add_host(shost, &dev->dev); | ||
577 | if (err) { | ||
578 | scsi_host_put(shost); | ||
579 | goto Err_free; | ||
580 | } | ||
581 | |||
582 | |||
583 | |||
584 | err = asd_dev->setup(asd_ha); | ||
585 | if (err) | ||
586 | goto Err_free; | ||
587 | |||
588 | err = -ENODEV; | ||
589 | if (!pci_set_dma_mask(dev, DMA_64BIT_MASK) | ||
590 | && !pci_set_consistent_dma_mask(dev, DMA_64BIT_MASK)) | ||
591 | ; | ||
592 | else if (!pci_set_dma_mask(dev, DMA_32BIT_MASK) | ||
593 | && !pci_set_consistent_dma_mask(dev, DMA_32BIT_MASK)) | ||
594 | ; | ||
595 | else { | ||
596 | asd_printk("no suitable DMA mask for %s\n", pci_name(dev)); | ||
597 | goto Err_free; | ||
598 | } | ||
599 | |||
600 | pci_set_drvdata(dev, asd_ha); | ||
601 | |||
602 | err = asd_map_ha(asd_ha); | ||
603 | if (err) | ||
604 | goto Err_free; | ||
605 | |||
606 | err = asd_create_ha_caches(asd_ha); | ||
607 | if (err) | ||
608 | goto Err_unmap; | ||
609 | |||
610 | err = asd_init_hw(asd_ha); | ||
611 | if (err) | ||
612 | goto Err_free_cache; | ||
613 | |||
614 | asd_printk("device %s: SAS addr %llx, PCBA SN %s, %d phys, %d enabled " | ||
615 | "phys, flash %s, BIOS %s%d\n", | ||
616 | pci_name(dev), SAS_ADDR(asd_ha->hw_prof.sas_addr), | ||
617 | asd_ha->hw_prof.pcba_sn, asd_ha->hw_prof.max_phys, | ||
618 | asd_ha->hw_prof.num_phys, | ||
619 | asd_ha->hw_prof.flash.present ? "present" : "not present", | ||
620 | asd_ha->hw_prof.bios.present ? "build " : "not present", | ||
621 | asd_ha->hw_prof.bios.bld); | ||
622 | |||
623 | if (use_msi) | ||
624 | pci_enable_msi(asd_ha->pcidev); | ||
625 | |||
626 | err = request_irq(asd_ha->pcidev->irq, asd_hw_isr, SA_SHIRQ, | ||
627 | ASD_DRIVER_NAME, asd_ha); | ||
628 | if (err) { | ||
629 | asd_printk("couldn't get irq %d for %s\n", | ||
630 | asd_ha->pcidev->irq, pci_name(asd_ha->pcidev)); | ||
631 | goto Err_irq; | ||
632 | } | ||
633 | asd_enable_ints(asd_ha); | ||
634 | |||
635 | err = asd_init_post_escbs(asd_ha); | ||
636 | if (err) { | ||
637 | asd_printk("couldn't post escbs for %s\n", | ||
638 | pci_name(asd_ha->pcidev)); | ||
639 | goto Err_escbs; | ||
640 | } | ||
641 | ASD_DPRINTK("escbs posted\n"); | ||
642 | |||
643 | asd_create_dev_attrs(asd_ha); | ||
644 | |||
645 | err = asd_register_sas_ha(asd_ha); | ||
646 | if (err) | ||
647 | goto Err_reg_sas; | ||
648 | |||
649 | err = asd_enable_phys(asd_ha, asd_ha->hw_prof.enabled_phys); | ||
650 | if (err) { | ||
651 | asd_printk("coudln't enable phys, err:%d\n", err); | ||
652 | goto Err_en_phys; | ||
653 | } | ||
654 | ASD_DPRINTK("enabled phys\n"); | ||
655 | /* give the phy enabling interrupt event time to come in (1s | ||
656 | * is empirically about all it takes) */ | ||
657 | ssleep(1); | ||
658 | /* Wait for discovery to finish */ | ||
659 | scsi_flush_work(asd_ha->sas_ha.core.shost); | ||
660 | |||
661 | return 0; | ||
662 | Err_en_phys: | ||
663 | asd_unregister_sas_ha(asd_ha); | ||
664 | Err_reg_sas: | ||
665 | asd_remove_dev_attrs(asd_ha); | ||
666 | Err_escbs: | ||
667 | asd_disable_ints(asd_ha); | ||
668 | free_irq(dev->irq, asd_ha); | ||
669 | Err_irq: | ||
670 | if (use_msi) | ||
671 | pci_disable_msi(dev); | ||
672 | asd_chip_hardrst(asd_ha); | ||
673 | Err_free_cache: | ||
674 | asd_destroy_ha_caches(asd_ha); | ||
675 | Err_unmap: | ||
676 | asd_unmap_ha(asd_ha); | ||
677 | Err_free: | ||
678 | kfree(asd_ha); | ||
679 | scsi_remove_host(shost); | ||
680 | Err: | ||
681 | pci_disable_device(dev); | ||
682 | return err; | ||
683 | } | ||
684 | |||
685 | static void asd_free_queues(struct asd_ha_struct *asd_ha) | ||
686 | { | ||
687 | unsigned long flags; | ||
688 | LIST_HEAD(pending); | ||
689 | struct list_head *n, *pos; | ||
690 | |||
691 | spin_lock_irqsave(&asd_ha->seq.pend_q_lock, flags); | ||
692 | asd_ha->seq.pending = 0; | ||
693 | list_splice_init(&asd_ha->seq.pend_q, &pending); | ||
694 | spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags); | ||
695 | |||
696 | if (!list_empty(&pending)) | ||
697 | ASD_DPRINTK("Uh-oh! Pending is not empty!\n"); | ||
698 | |||
699 | list_for_each_safe(pos, n, &pending) { | ||
700 | struct asd_ascb *ascb = list_entry(pos, struct asd_ascb, list); | ||
701 | list_del_init(pos); | ||
702 | ASD_DPRINTK("freeing from pending\n"); | ||
703 | asd_ascb_free(ascb); | ||
704 | } | ||
705 | } | ||
706 | |||
707 | static void asd_turn_off_leds(struct asd_ha_struct *asd_ha) | ||
708 | { | ||
709 | u8 phy_mask = asd_ha->hw_prof.enabled_phys; | ||
710 | u8 i; | ||
711 | |||
712 | for_each_phy(phy_mask, phy_mask, i) { | ||
713 | asd_turn_led(asd_ha, i, 0); | ||
714 | asd_control_led(asd_ha, i, 0); | ||
715 | } | ||
716 | } | ||
717 | |||
718 | static void __devexit asd_pci_remove(struct pci_dev *dev) | ||
719 | { | ||
720 | struct asd_ha_struct *asd_ha = pci_get_drvdata(dev); | ||
721 | |||
722 | if (!asd_ha) | ||
723 | return; | ||
724 | |||
725 | asd_unregister_sas_ha(asd_ha); | ||
726 | |||
727 | asd_disable_ints(asd_ha); | ||
728 | |||
729 | asd_remove_dev_attrs(asd_ha); | ||
730 | |||
731 | /* XXX more here as needed */ | ||
732 | |||
733 | free_irq(dev->irq, asd_ha); | ||
734 | if (use_msi) | ||
735 | pci_disable_msi(asd_ha->pcidev); | ||
736 | asd_turn_off_leds(asd_ha); | ||
737 | asd_chip_hardrst(asd_ha); | ||
738 | asd_free_queues(asd_ha); | ||
739 | asd_destroy_ha_caches(asd_ha); | ||
740 | asd_unmap_ha(asd_ha); | ||
741 | kfree(asd_ha); | ||
742 | pci_disable_device(dev); | ||
743 | return; | ||
744 | } | ||
745 | |||
746 | static ssize_t asd_version_show(struct device_driver *driver, char *buf) | ||
747 | { | ||
748 | return snprintf(buf, PAGE_SIZE, "%s\n", ASD_DRIVER_VERSION); | ||
749 | } | ||
750 | static DRIVER_ATTR(version, S_IRUGO, asd_version_show, NULL); | ||
751 | |||
752 | static void asd_create_driver_attrs(struct device_driver *driver) | ||
753 | { | ||
754 | driver_create_file(driver, &driver_attr_version); | ||
755 | } | ||
756 | |||
757 | static void asd_remove_driver_attrs(struct device_driver *driver) | ||
758 | { | ||
759 | driver_remove_file(driver, &driver_attr_version); | ||
760 | } | ||
761 | |||
762 | static struct sas_domain_function_template aic94xx_transport_functions = { | ||
763 | .lldd_port_formed = asd_update_port_links, | ||
764 | |||
765 | .lldd_dev_found = asd_dev_found, | ||
766 | .lldd_dev_gone = asd_dev_gone, | ||
767 | |||
768 | .lldd_execute_task = asd_execute_task, | ||
769 | |||
770 | .lldd_abort_task = asd_abort_task, | ||
771 | .lldd_abort_task_set = asd_abort_task_set, | ||
772 | .lldd_clear_aca = asd_clear_aca, | ||
773 | .lldd_clear_task_set = asd_clear_task_set, | ||
774 | .lldd_I_T_nexus_reset = NULL, | ||
775 | .lldd_lu_reset = asd_lu_reset, | ||
776 | .lldd_query_task = asd_query_task, | ||
777 | |||
778 | .lldd_clear_nexus_port = asd_clear_nexus_port, | ||
779 | .lldd_clear_nexus_ha = asd_clear_nexus_ha, | ||
780 | |||
781 | .lldd_control_phy = asd_control_phy, | ||
782 | }; | ||
783 | |||
784 | static const struct pci_device_id aic94xx_pci_table[] __devinitdata = { | ||
785 | {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR10), | ||
786 | 0, 0, 1}, | ||
787 | {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR12), | ||
788 | 0, 0, 1}, | ||
789 | {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR1E), | ||
790 | 0, 0, 1}, | ||
791 | {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR30), | ||
792 | 0, 0, 2}, | ||
793 | {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR32), | ||
794 | 0, 0, 2}, | ||
795 | {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR3E), | ||
796 | 0, 0, 2}, | ||
797 | {PCI_DEVICE(PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_RAZOR3F), | ||
798 | 0, 0, 2}, | ||
799 | {} | ||
800 | }; | ||
801 | |||
802 | MODULE_DEVICE_TABLE(pci, aic94xx_pci_table); | ||
803 | |||
804 | static struct pci_driver aic94xx_pci_driver = { | ||
805 | .name = ASD_DRIVER_NAME, | ||
806 | .id_table = aic94xx_pci_table, | ||
807 | .probe = asd_pci_probe, | ||
808 | .remove = __devexit_p(asd_pci_remove), | ||
809 | }; | ||
810 | |||
811 | static int __init aic94xx_init(void) | ||
812 | { | ||
813 | int err; | ||
814 | |||
815 | |||
816 | asd_printk("%s version %s loaded\n", ASD_DRIVER_DESCRIPTION, | ||
817 | ASD_DRIVER_VERSION); | ||
818 | |||
819 | err = asd_create_global_caches(); | ||
820 | if (err) | ||
821 | return err; | ||
822 | |||
823 | aic94xx_transport_template = | ||
824 | sas_domain_attach_transport(&aic94xx_transport_functions); | ||
825 | if (err) | ||
826 | goto out_destroy_caches; | ||
827 | |||
828 | err = pci_register_driver(&aic94xx_pci_driver); | ||
829 | if (err) | ||
830 | goto out_release_transport; | ||
831 | |||
832 | asd_create_driver_attrs(&aic94xx_pci_driver.driver); | ||
833 | |||
834 | return err; | ||
835 | |||
836 | out_release_transport: | ||
837 | sas_release_transport(aic94xx_transport_template); | ||
838 | out_destroy_caches: | ||
839 | asd_destroy_global_caches(); | ||
840 | |||
841 | return err; | ||
842 | } | ||
843 | |||
844 | static void __exit aic94xx_exit(void) | ||
845 | { | ||
846 | asd_remove_driver_attrs(&aic94xx_pci_driver.driver); | ||
847 | pci_unregister_driver(&aic94xx_pci_driver); | ||
848 | sas_release_transport(aic94xx_transport_template); | ||
849 | asd_destroy_global_caches(); | ||
850 | asd_printk("%s version %s unloaded\n", ASD_DRIVER_DESCRIPTION, | ||
851 | ASD_DRIVER_VERSION); | ||
852 | } | ||
853 | |||
854 | module_init(aic94xx_init); | ||
855 | module_exit(aic94xx_exit); | ||
856 | |||
857 | MODULE_AUTHOR("Luben Tuikov <luben_tuikov@adaptec.com>"); | ||
858 | MODULE_DESCRIPTION(ASD_DRIVER_DESCRIPTION); | ||
859 | MODULE_LICENSE("GPL v2"); | ||
860 | MODULE_VERSION(ASD_DRIVER_VERSION); | ||
diff --git a/drivers/scsi/aic94xx/aic94xx_reg.c b/drivers/scsi/aic94xx/aic94xx_reg.c new file mode 100644 index 000000000000..f210dac3203d --- /dev/null +++ b/drivers/scsi/aic94xx/aic94xx_reg.c | |||
@@ -0,0 +1,332 @@ | |||
1 | /* | ||
2 | * Aic94xx SAS/SATA driver register access. | ||
3 | * | ||
4 | * Copyright (C) 2005 Adaptec, Inc. All rights reserved. | ||
5 | * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> | ||
6 | * | ||
7 | * This file is licensed under GPLv2. | ||
8 | * | ||
9 | * This file is part of the aic94xx driver. | ||
10 | * | ||
11 | * The aic94xx driver is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License as | ||
13 | * published by the Free Software Foundation; version 2 of the | ||
14 | * License. | ||
15 | * | ||
16 | * The aic94xx driver is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
19 | * General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with the aic94xx driver; if not, write to the Free Software | ||
23 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #include <linux/pci.h> | ||
28 | #include "aic94xx_reg.h" | ||
29 | #include "aic94xx.h" | ||
30 | |||
31 | /* Writing to device address space. | ||
32 | * Offset comes before value to remind that the operation of | ||
33 | * this function is *offs = val. | ||
34 | */ | ||
35 | static inline void asd_write_byte(struct asd_ha_struct *asd_ha, | ||
36 | unsigned long offs, u8 val) | ||
37 | { | ||
38 | if (unlikely(asd_ha->iospace)) | ||
39 | outb(val, | ||
40 | (unsigned long)asd_ha->io_handle[0].addr + (offs & 0xFF)); | ||
41 | else | ||
42 | writeb(val, asd_ha->io_handle[0].addr + offs); | ||
43 | wmb(); | ||
44 | } | ||
45 | |||
46 | static inline void asd_write_word(struct asd_ha_struct *asd_ha, | ||
47 | unsigned long offs, u16 val) | ||
48 | { | ||
49 | if (unlikely(asd_ha->iospace)) | ||
50 | outw(val, | ||
51 | (unsigned long)asd_ha->io_handle[0].addr + (offs & 0xFF)); | ||
52 | else | ||
53 | writew(val, asd_ha->io_handle[0].addr + offs); | ||
54 | wmb(); | ||
55 | } | ||
56 | |||
57 | static inline void asd_write_dword(struct asd_ha_struct *asd_ha, | ||
58 | unsigned long offs, u32 val) | ||
59 | { | ||
60 | if (unlikely(asd_ha->iospace)) | ||
61 | outl(val, | ||
62 | (unsigned long)asd_ha->io_handle[0].addr + (offs & 0xFF)); | ||
63 | else | ||
64 | writel(val, asd_ha->io_handle[0].addr + offs); | ||
65 | wmb(); | ||
66 | } | ||
67 | |||
68 | /* Reading from device address space. | ||
69 | */ | ||
70 | static inline u8 asd_read_byte(struct asd_ha_struct *asd_ha, | ||
71 | unsigned long offs) | ||
72 | { | ||
73 | u8 val; | ||
74 | if (unlikely(asd_ha->iospace)) | ||
75 | val = inb((unsigned long) asd_ha->io_handle[0].addr | ||
76 | + (offs & 0xFF)); | ||
77 | else | ||
78 | val = readb(asd_ha->io_handle[0].addr + offs); | ||
79 | rmb(); | ||
80 | return val; | ||
81 | } | ||
82 | |||
83 | static inline u16 asd_read_word(struct asd_ha_struct *asd_ha, | ||
84 | unsigned long offs) | ||
85 | { | ||
86 | u16 val; | ||
87 | if (unlikely(asd_ha->iospace)) | ||
88 | val = inw((unsigned long)asd_ha->io_handle[0].addr | ||
89 | + (offs & 0xFF)); | ||
90 | else | ||
91 | val = readw(asd_ha->io_handle[0].addr + offs); | ||
92 | rmb(); | ||
93 | return val; | ||
94 | } | ||
95 | |||
96 | static inline u32 asd_read_dword(struct asd_ha_struct *asd_ha, | ||
97 | unsigned long offs) | ||
98 | { | ||
99 | u32 val; | ||
100 | if (unlikely(asd_ha->iospace)) | ||
101 | val = inl((unsigned long) asd_ha->io_handle[0].addr | ||
102 | + (offs & 0xFF)); | ||
103 | else | ||
104 | val = readl(asd_ha->io_handle[0].addr + offs); | ||
105 | rmb(); | ||
106 | return val; | ||
107 | } | ||
108 | |||
109 | static inline u32 asd_mem_offs_swa(void) | ||
110 | { | ||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | static inline u32 asd_mem_offs_swc(void) | ||
115 | { | ||
116 | return asd_mem_offs_swa() + MBAR0_SWA_SIZE; | ||
117 | } | ||
118 | |||
119 | static inline u32 asd_mem_offs_swb(void) | ||
120 | { | ||
121 | return asd_mem_offs_swc() + MBAR0_SWC_SIZE + 0x20; | ||
122 | } | ||
123 | |||
124 | /* We know that the register wanted is in the range | ||
125 | * of the sliding window. | ||
126 | */ | ||
127 | #define ASD_READ_SW(ww, type, ord) \ | ||
128 | static inline type asd_read_##ww##_##ord (struct asd_ha_struct *asd_ha,\ | ||
129 | u32 reg) \ | ||
130 | { \ | ||
131 | struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0]; \ | ||
132 | u32 map_offs=(reg - io_handle-> ww##_base )+asd_mem_offs_##ww ();\ | ||
133 | return asd_read_##ord (asd_ha, (unsigned long) map_offs); \ | ||
134 | } | ||
135 | |||
136 | #define ASD_WRITE_SW(ww, type, ord) \ | ||
137 | static inline void asd_write_##ww##_##ord (struct asd_ha_struct *asd_ha,\ | ||
138 | u32 reg, type val) \ | ||
139 | { \ | ||
140 | struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[0]; \ | ||
141 | u32 map_offs=(reg - io_handle-> ww##_base )+asd_mem_offs_##ww ();\ | ||
142 | asd_write_##ord (asd_ha, (unsigned long) map_offs, val); \ | ||
143 | } | ||
144 | |||
145 | ASD_READ_SW(swa, u8, byte); | ||
146 | ASD_READ_SW(swa, u16, word); | ||
147 | ASD_READ_SW(swa, u32, dword); | ||
148 | |||
149 | ASD_READ_SW(swb, u8, byte); | ||
150 | ASD_READ_SW(swb, u16, word); | ||
151 | ASD_READ_SW(swb, u32, dword); | ||
152 | |||
153 | ASD_READ_SW(swc, u8, byte); | ||
154 | ASD_READ_SW(swc, u16, word); | ||
155 | ASD_READ_SW(swc, u32, dword); | ||
156 | |||
157 | ASD_WRITE_SW(swa, u8, byte); | ||
158 | ASD_WRITE_SW(swa, u16, word); | ||
159 | ASD_WRITE_SW(swa, u32, dword); | ||
160 | |||
161 | ASD_WRITE_SW(swb, u8, byte); | ||
162 | ASD_WRITE_SW(swb, u16, word); | ||
163 | ASD_WRITE_SW(swb, u32, dword); | ||
164 | |||
165 | ASD_WRITE_SW(swc, u8, byte); | ||
166 | ASD_WRITE_SW(swc, u16, word); | ||
167 | ASD_WRITE_SW(swc, u32, dword); | ||
168 | |||
169 | /* | ||
170 | * A word about sliding windows: | ||
171 | * MBAR0 is divided into sliding windows A, C and B, in that order. | ||
172 | * SWA starts at offset 0 of MBAR0, up to 0x57, with size 0x58 bytes. | ||
173 | * SWC starts at offset 0x58 of MBAR0, up to 0x60, with size 0x8 bytes. | ||
174 | * From 0x60 to 0x7F, we have a copy of PCI config space 0x60-0x7F. | ||
175 | * SWB starts at offset 0x80 of MBAR0 and extends to the end of MBAR0. | ||
176 | * See asd_init_sw() in aic94xx_hwi.c | ||
177 | * | ||
178 | * We map the most common registers we'd access of the internal 4GB | ||
179 | * host adapter memory space. If a register/internal memory location | ||
180 | * is wanted which is not mapped, we slide SWB, by paging it, | ||
181 | * see asd_move_swb() in aic94xx_reg.c. | ||
182 | */ | ||
183 | |||
184 | /** | ||
185 | * asd_move_swb -- move sliding window B | ||
186 | * @asd_ha: pointer to host adapter structure | ||
187 | * @reg: register desired to be within range of the new window | ||
188 | */ | ||
189 | static inline void asd_move_swb(struct asd_ha_struct *asd_ha, u32 reg) | ||
190 | { | ||
191 | u32 base = reg & ~(MBAR0_SWB_SIZE-1); | ||
192 | pci_write_config_dword(asd_ha->pcidev, PCI_CONF_MBAR0_SWB, base); | ||
193 | asd_ha->io_handle[0].swb_base = base; | ||
194 | } | ||
195 | |||
196 | static void __asd_write_reg_byte(struct asd_ha_struct *asd_ha, u32 reg, u8 val) | ||
197 | { | ||
198 | struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0]; | ||
199 | BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR); | ||
200 | if (io_handle->swa_base <= reg | ||
201 | && reg < io_handle->swa_base + MBAR0_SWA_SIZE) | ||
202 | asd_write_swa_byte (asd_ha, reg,val); | ||
203 | else if (io_handle->swb_base <= reg | ||
204 | && reg < io_handle->swb_base + MBAR0_SWB_SIZE) | ||
205 | asd_write_swb_byte (asd_ha, reg, val); | ||
206 | else if (io_handle->swc_base <= reg | ||
207 | && reg < io_handle->swc_base + MBAR0_SWC_SIZE) | ||
208 | asd_write_swc_byte (asd_ha, reg, val); | ||
209 | else { | ||
210 | /* Ok, we have to move SWB */ | ||
211 | asd_move_swb(asd_ha, reg); | ||
212 | asd_write_swb_byte (asd_ha, reg, val); | ||
213 | } | ||
214 | } | ||
215 | |||
216 | #define ASD_WRITE_REG(type, ord) \ | ||
217 | void asd_write_reg_##ord (struct asd_ha_struct *asd_ha, u32 reg, type val)\ | ||
218 | { \ | ||
219 | struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0]; \ | ||
220 | unsigned long flags; \ | ||
221 | BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR); \ | ||
222 | spin_lock_irqsave(&asd_ha->iolock, flags); \ | ||
223 | if (io_handle->swa_base <= reg \ | ||
224 | && reg < io_handle->swa_base + MBAR0_SWA_SIZE) \ | ||
225 | asd_write_swa_##ord (asd_ha, reg,val); \ | ||
226 | else if (io_handle->swb_base <= reg \ | ||
227 | && reg < io_handle->swb_base + MBAR0_SWB_SIZE) \ | ||
228 | asd_write_swb_##ord (asd_ha, reg, val); \ | ||
229 | else if (io_handle->swc_base <= reg \ | ||
230 | && reg < io_handle->swc_base + MBAR0_SWC_SIZE) \ | ||
231 | asd_write_swc_##ord (asd_ha, reg, val); \ | ||
232 | else { \ | ||
233 | /* Ok, we have to move SWB */ \ | ||
234 | asd_move_swb(asd_ha, reg); \ | ||
235 | asd_write_swb_##ord (asd_ha, reg, val); \ | ||
236 | } \ | ||
237 | spin_unlock_irqrestore(&asd_ha->iolock, flags); \ | ||
238 | } | ||
239 | |||
240 | ASD_WRITE_REG(u8, byte); | ||
241 | ASD_WRITE_REG(u16,word); | ||
242 | ASD_WRITE_REG(u32,dword); | ||
243 | |||
244 | static u8 __asd_read_reg_byte(struct asd_ha_struct *asd_ha, u32 reg) | ||
245 | { | ||
246 | struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0]; | ||
247 | u8 val; | ||
248 | BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR); | ||
249 | if (io_handle->swa_base <= reg | ||
250 | && reg < io_handle->swa_base + MBAR0_SWA_SIZE) | ||
251 | val = asd_read_swa_byte (asd_ha, reg); | ||
252 | else if (io_handle->swb_base <= reg | ||
253 | && reg < io_handle->swb_base + MBAR0_SWB_SIZE) | ||
254 | val = asd_read_swb_byte (asd_ha, reg); | ||
255 | else if (io_handle->swc_base <= reg | ||
256 | && reg < io_handle->swc_base + MBAR0_SWC_SIZE) | ||
257 | val = asd_read_swc_byte (asd_ha, reg); | ||
258 | else { | ||
259 | /* Ok, we have to move SWB */ | ||
260 | asd_move_swb(asd_ha, reg); | ||
261 | val = asd_read_swb_byte (asd_ha, reg); | ||
262 | } | ||
263 | return val; | ||
264 | } | ||
265 | |||
266 | #define ASD_READ_REG(type, ord) \ | ||
267 | type asd_read_reg_##ord (struct asd_ha_struct *asd_ha, u32 reg) \ | ||
268 | { \ | ||
269 | struct asd_ha_addrspace *io_handle=&asd_ha->io_handle[0]; \ | ||
270 | type val; \ | ||
271 | unsigned long flags; \ | ||
272 | BUG_ON(reg >= 0xC0000000 || reg < ALL_BASE_ADDR); \ | ||
273 | spin_lock_irqsave(&asd_ha->iolock, flags); \ | ||
274 | if (io_handle->swa_base <= reg \ | ||
275 | && reg < io_handle->swa_base + MBAR0_SWA_SIZE) \ | ||
276 | val = asd_read_swa_##ord (asd_ha, reg); \ | ||
277 | else if (io_handle->swb_base <= reg \ | ||
278 | && reg < io_handle->swb_base + MBAR0_SWB_SIZE) \ | ||
279 | val = asd_read_swb_##ord (asd_ha, reg); \ | ||
280 | else if (io_handle->swc_base <= reg \ | ||
281 | && reg < io_handle->swc_base + MBAR0_SWC_SIZE) \ | ||
282 | val = asd_read_swc_##ord (asd_ha, reg); \ | ||
283 | else { \ | ||
284 | /* Ok, we have to move SWB */ \ | ||
285 | asd_move_swb(asd_ha, reg); \ | ||
286 | val = asd_read_swb_##ord (asd_ha, reg); \ | ||
287 | } \ | ||
288 | spin_unlock_irqrestore(&asd_ha->iolock, flags); \ | ||
289 | return val; \ | ||
290 | } | ||
291 | |||
292 | ASD_READ_REG(u8, byte); | ||
293 | ASD_READ_REG(u16,word); | ||
294 | ASD_READ_REG(u32,dword); | ||
295 | |||
296 | /** | ||
297 | * asd_read_reg_string -- read a string of bytes from io space memory | ||
298 | * @asd_ha: pointer to host adapter structure | ||
299 | * @dst: pointer to a destination buffer where data will be written to | ||
300 | * @offs: start offset (register) to read from | ||
301 | * @count: number of bytes to read | ||
302 | */ | ||
303 | void asd_read_reg_string(struct asd_ha_struct *asd_ha, void *dst, | ||
304 | u32 offs, int count) | ||
305 | { | ||
306 | u8 *p = dst; | ||
307 | unsigned long flags; | ||
308 | |||
309 | spin_lock_irqsave(&asd_ha->iolock, flags); | ||
310 | for ( ; count > 0; count--, offs++, p++) | ||
311 | *p = __asd_read_reg_byte(asd_ha, offs); | ||
312 | spin_unlock_irqrestore(&asd_ha->iolock, flags); | ||
313 | } | ||
314 | |||
315 | /** | ||
316 | * asd_write_reg_string -- write a string of bytes to io space memory | ||
317 | * @asd_ha: pointer to host adapter structure | ||
318 | * @src: pointer to source buffer where data will be read from | ||
319 | * @offs: start offset (register) to write to | ||
320 | * @count: number of bytes to write | ||
321 | */ | ||
322 | void asd_write_reg_string(struct asd_ha_struct *asd_ha, void *src, | ||
323 | u32 offs, int count) | ||
324 | { | ||
325 | u8 *p = src; | ||
326 | unsigned long flags; | ||
327 | |||
328 | spin_lock_irqsave(&asd_ha->iolock, flags); | ||
329 | for ( ; count > 0; count--, offs++, p++) | ||
330 | __asd_write_reg_byte(asd_ha, offs, *p); | ||
331 | spin_unlock_irqrestore(&asd_ha->iolock, flags); | ||
332 | } | ||
diff --git a/drivers/scsi/aic94xx/aic94xx_reg.h b/drivers/scsi/aic94xx/aic94xx_reg.h new file mode 100644 index 000000000000..2279307fd27e --- /dev/null +++ b/drivers/scsi/aic94xx/aic94xx_reg.h | |||
@@ -0,0 +1,302 @@ | |||
1 | /* | ||
2 | * Aic94xx SAS/SATA driver hardware registers definitions. | ||
3 | * | ||
4 | * Copyright (C) 2005 Adaptec, Inc. All rights reserved. | ||
5 | * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> | ||
6 | * | ||
7 | * This file is licensed under GPLv2. | ||
8 | * | ||
9 | * This file is part of the aic94xx driver. | ||
10 | * | ||
11 | * The aic94xx driver is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License as | ||
13 | * published by the Free Software Foundation; version 2 of the | ||
14 | * License. | ||
15 | * | ||
16 | * The aic94xx driver is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
19 | * General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with the aic94xx driver; if not, write to the Free Software | ||
23 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #ifndef _AIC94XX_REG_H_ | ||
28 | #define _AIC94XX_REG_H_ | ||
29 | |||
30 | #include <asm/io.h> | ||
31 | #include "aic94xx_hwi.h" | ||
32 | |||
33 | /* Values */ | ||
34 | #define AIC9410_DEV_REV_B0 0x8 | ||
35 | |||
36 | /* MBAR0, SWA, SWB, SWC, internal memory space addresses */ | ||
37 | #define REG_BASE_ADDR 0xB8000000 | ||
38 | #define REG_BASE_ADDR_CSEQCIO 0xB8002000 | ||
39 | #define REG_BASE_ADDR_EXSI 0xB8042800 | ||
40 | |||
41 | #define MBAR0_SWA_SIZE 0x58 | ||
42 | extern u32 MBAR0_SWB_SIZE; | ||
43 | #define MBAR0_SWC_SIZE 0x8 | ||
44 | |||
45 | /* MBAR1, points to On Chip Memory */ | ||
46 | #define OCM_BASE_ADDR 0xA0000000 | ||
47 | #define OCM_MAX_SIZE 0x20000 | ||
48 | |||
49 | /* Smallest address possible to reference */ | ||
50 | #define ALL_BASE_ADDR OCM_BASE_ADDR | ||
51 | |||
52 | /* PCI configuration space registers */ | ||
53 | #define PCI_IOBAR_OFFSET 4 | ||
54 | |||
55 | #define PCI_CONF_MBAR1 0x6C | ||
56 | #define PCI_CONF_MBAR0_SWA 0x70 | ||
57 | #define PCI_CONF_MBAR0_SWB 0x74 | ||
58 | #define PCI_CONF_MBAR0_SWC 0x78 | ||
59 | #define PCI_CONF_MBAR_KEY 0x7C | ||
60 | #define PCI_CONF_FLSH_BAR 0xB8 | ||
61 | |||
62 | #include "aic94xx_reg_def.h" | ||
63 | |||
64 | u8 asd_read_reg_byte(struct asd_ha_struct *asd_ha, u32 reg); | ||
65 | u16 asd_read_reg_word(struct asd_ha_struct *asd_ha, u32 reg); | ||
66 | u32 asd_read_reg_dword(struct asd_ha_struct *asd_ha, u32 reg); | ||
67 | |||
68 | void asd_write_reg_byte(struct asd_ha_struct *asd_ha, u32 reg, u8 val); | ||
69 | void asd_write_reg_word(struct asd_ha_struct *asd_ha, u32 reg, u16 val); | ||
70 | void asd_write_reg_dword(struct asd_ha_struct *asd_ha, u32 reg, u32 val); | ||
71 | |||
72 | void asd_read_reg_string(struct asd_ha_struct *asd_ha, void *dst, | ||
73 | u32 offs, int count); | ||
74 | void asd_write_reg_string(struct asd_ha_struct *asd_ha, void *src, | ||
75 | u32 offs, int count); | ||
76 | |||
77 | #define ASD_READ_OCM(type, ord, S) \ | ||
78 | static inline type asd_read_ocm_##ord (struct asd_ha_struct *asd_ha, \ | ||
79 | u32 offs) \ | ||
80 | { \ | ||
81 | struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[1]; \ | ||
82 | type val = read##S (io_handle->addr + (unsigned long) offs); \ | ||
83 | rmb(); \ | ||
84 | return val; \ | ||
85 | } | ||
86 | |||
87 | ASD_READ_OCM(u8, byte, b); | ||
88 | ASD_READ_OCM(u16,word, w); | ||
89 | ASD_READ_OCM(u32,dword,l); | ||
90 | |||
91 | #define ASD_WRITE_OCM(type, ord, S) \ | ||
92 | static inline void asd_write_ocm_##ord (struct asd_ha_struct *asd_ha, \ | ||
93 | u32 offs, type val) \ | ||
94 | { \ | ||
95 | struct asd_ha_addrspace *io_handle = &asd_ha->io_handle[1]; \ | ||
96 | write##S (val, io_handle->addr + (unsigned long) offs); \ | ||
97 | return; \ | ||
98 | } | ||
99 | |||
100 | ASD_WRITE_OCM(u8, byte, b); | ||
101 | ASD_WRITE_OCM(u16,word, w); | ||
102 | ASD_WRITE_OCM(u32,dword,l); | ||
103 | |||
104 | #define ASD_DDBSITE_READ(type, ord) \ | ||
105 | static inline type asd_ddbsite_read_##ord (struct asd_ha_struct *asd_ha, \ | ||
106 | u16 ddb_site_no, \ | ||
107 | u16 offs) \ | ||
108 | { \ | ||
109 | asd_write_reg_word(asd_ha, ALTCIOADR, MnDDB_SITE + offs); \ | ||
110 | asd_write_reg_word(asd_ha, ADDBPTR, ddb_site_no); \ | ||
111 | return asd_read_reg_##ord (asd_ha, CTXACCESS); \ | ||
112 | } | ||
113 | |||
114 | ASD_DDBSITE_READ(u32, dword); | ||
115 | ASD_DDBSITE_READ(u16, word); | ||
116 | |||
117 | static inline u8 asd_ddbsite_read_byte(struct asd_ha_struct *asd_ha, | ||
118 | u16 ddb_site_no, | ||
119 | u16 offs) | ||
120 | { | ||
121 | if (offs & 1) | ||
122 | return asd_ddbsite_read_word(asd_ha, ddb_site_no, | ||
123 | offs & ~1) >> 8; | ||
124 | else | ||
125 | return asd_ddbsite_read_word(asd_ha, ddb_site_no, | ||
126 | offs) & 0xFF; | ||
127 | } | ||
128 | |||
129 | |||
130 | #define ASD_DDBSITE_WRITE(type, ord) \ | ||
131 | static inline void asd_ddbsite_write_##ord (struct asd_ha_struct *asd_ha, \ | ||
132 | u16 ddb_site_no, \ | ||
133 | u16 offs, type val) \ | ||
134 | { \ | ||
135 | asd_write_reg_word(asd_ha, ALTCIOADR, MnDDB_SITE + offs); \ | ||
136 | asd_write_reg_word(asd_ha, ADDBPTR, ddb_site_no); \ | ||
137 | asd_write_reg_##ord (asd_ha, CTXACCESS, val); \ | ||
138 | } | ||
139 | |||
140 | ASD_DDBSITE_WRITE(u32, dword); | ||
141 | ASD_DDBSITE_WRITE(u16, word); | ||
142 | |||
143 | static inline void asd_ddbsite_write_byte(struct asd_ha_struct *asd_ha, | ||
144 | u16 ddb_site_no, | ||
145 | u16 offs, u8 val) | ||
146 | { | ||
147 | u16 base = offs & ~1; | ||
148 | u16 rval = asd_ddbsite_read_word(asd_ha, ddb_site_no, base); | ||
149 | if (offs & 1) | ||
150 | rval = (val << 8) | (rval & 0xFF); | ||
151 | else | ||
152 | rval = (rval & 0xFF00) | val; | ||
153 | asd_ddbsite_write_word(asd_ha, ddb_site_no, base, rval); | ||
154 | } | ||
155 | |||
156 | |||
157 | #define ASD_SCBSITE_READ(type, ord) \ | ||
158 | static inline type asd_scbsite_read_##ord (struct asd_ha_struct *asd_ha, \ | ||
159 | u16 scb_site_no, \ | ||
160 | u16 offs) \ | ||
161 | { \ | ||
162 | asd_write_reg_word(asd_ha, ALTCIOADR, MnSCB_SITE + offs); \ | ||
163 | asd_write_reg_word(asd_ha, ASCBPTR, scb_site_no); \ | ||
164 | return asd_read_reg_##ord (asd_ha, CTXACCESS); \ | ||
165 | } | ||
166 | |||
167 | ASD_SCBSITE_READ(u32, dword); | ||
168 | ASD_SCBSITE_READ(u16, word); | ||
169 | |||
170 | static inline u8 asd_scbsite_read_byte(struct asd_ha_struct *asd_ha, | ||
171 | u16 scb_site_no, | ||
172 | u16 offs) | ||
173 | { | ||
174 | if (offs & 1) | ||
175 | return asd_scbsite_read_word(asd_ha, scb_site_no, | ||
176 | offs & ~1) >> 8; | ||
177 | else | ||
178 | return asd_scbsite_read_word(asd_ha, scb_site_no, | ||
179 | offs) & 0xFF; | ||
180 | } | ||
181 | |||
182 | |||
183 | #define ASD_SCBSITE_WRITE(type, ord) \ | ||
184 | static inline void asd_scbsite_write_##ord (struct asd_ha_struct *asd_ha, \ | ||
185 | u16 scb_site_no, \ | ||
186 | u16 offs, type val) \ | ||
187 | { \ | ||
188 | asd_write_reg_word(asd_ha, ALTCIOADR, MnSCB_SITE + offs); \ | ||
189 | asd_write_reg_word(asd_ha, ASCBPTR, scb_site_no); \ | ||
190 | asd_write_reg_##ord (asd_ha, CTXACCESS, val); \ | ||
191 | } | ||
192 | |||
193 | ASD_SCBSITE_WRITE(u32, dword); | ||
194 | ASD_SCBSITE_WRITE(u16, word); | ||
195 | |||
196 | static inline void asd_scbsite_write_byte(struct asd_ha_struct *asd_ha, | ||
197 | u16 scb_site_no, | ||
198 | u16 offs, u8 val) | ||
199 | { | ||
200 | u16 base = offs & ~1; | ||
201 | u16 rval = asd_scbsite_read_word(asd_ha, scb_site_no, base); | ||
202 | if (offs & 1) | ||
203 | rval = (val << 8) | (rval & 0xFF); | ||
204 | else | ||
205 | rval = (rval & 0xFF00) | val; | ||
206 | asd_scbsite_write_word(asd_ha, scb_site_no, base, rval); | ||
207 | } | ||
208 | |||
209 | /** | ||
210 | * asd_ddbsite_update_word -- atomically update a word in a ddb site | ||
211 | * @asd_ha: pointer to host adapter structure | ||
212 | * @ddb_site_no: the DDB site number | ||
213 | * @offs: the offset into the DDB | ||
214 | * @oldval: old value found in that offset | ||
215 | * @newval: the new value to replace it | ||
216 | * | ||
217 | * This function is used when the sequencers are running and we need to | ||
218 | * update a DDB site atomically without expensive pausing and upausing | ||
219 | * of the sequencers and accessing the DDB site through the CIO bus. | ||
220 | * | ||
221 | * Return 0 on success; -EFAULT on parity error; -EAGAIN if the old value | ||
222 | * is different than the current value at that offset. | ||
223 | */ | ||
224 | static inline int asd_ddbsite_update_word(struct asd_ha_struct *asd_ha, | ||
225 | u16 ddb_site_no, u16 offs, | ||
226 | u16 oldval, u16 newval) | ||
227 | { | ||
228 | u8 done; | ||
229 | u16 oval = asd_ddbsite_read_word(asd_ha, ddb_site_no, offs); | ||
230 | if (oval != oldval) | ||
231 | return -EAGAIN; | ||
232 | asd_write_reg_word(asd_ha, AOLDDATA, oldval); | ||
233 | asd_write_reg_word(asd_ha, ANEWDATA, newval); | ||
234 | do { | ||
235 | done = asd_read_reg_byte(asd_ha, ATOMICSTATCTL); | ||
236 | } while (!(done & ATOMICDONE)); | ||
237 | if (done & ATOMICERR) | ||
238 | return -EFAULT; /* parity error */ | ||
239 | else if (done & ATOMICWIN) | ||
240 | return 0; /* success */ | ||
241 | else | ||
242 | return -EAGAIN; /* oldval different than current value */ | ||
243 | } | ||
244 | |||
245 | static inline int asd_ddbsite_update_byte(struct asd_ha_struct *asd_ha, | ||
246 | u16 ddb_site_no, u16 offs, | ||
247 | u8 _oldval, u8 _newval) | ||
248 | { | ||
249 | u16 base = offs & ~1; | ||
250 | u16 oval; | ||
251 | u16 nval = asd_ddbsite_read_word(asd_ha, ddb_site_no, base); | ||
252 | if (offs & 1) { | ||
253 | if ((nval >> 8) != _oldval) | ||
254 | return -EAGAIN; | ||
255 | nval = (_newval << 8) | (nval & 0xFF); | ||
256 | oval = (_oldval << 8) | (nval & 0xFF); | ||
257 | } else { | ||
258 | if ((nval & 0xFF) != _oldval) | ||
259 | return -EAGAIN; | ||
260 | nval = (nval & 0xFF00) | _newval; | ||
261 | oval = (nval & 0xFF00) | _oldval; | ||
262 | } | ||
263 | return asd_ddbsite_update_word(asd_ha, ddb_site_no, base, oval, nval); | ||
264 | } | ||
265 | |||
266 | static inline void asd_write_reg_addr(struct asd_ha_struct *asd_ha, u32 reg, | ||
267 | dma_addr_t dma_handle) | ||
268 | { | ||
269 | asd_write_reg_dword(asd_ha, reg, ASD_BUSADDR_LO(dma_handle)); | ||
270 | asd_write_reg_dword(asd_ha, reg+4, ASD_BUSADDR_HI(dma_handle)); | ||
271 | } | ||
272 | |||
273 | static inline u32 asd_get_cmdctx_size(struct asd_ha_struct *asd_ha) | ||
274 | { | ||
275 | /* DCHREVISION returns 0, possibly broken */ | ||
276 | u32 ctxmemsize = asd_read_reg_dword(asd_ha, LmMnINT(0,0)) & CTXMEMSIZE; | ||
277 | return ctxmemsize ? 65536 : 32768; | ||
278 | } | ||
279 | |||
280 | static inline u32 asd_get_devctx_size(struct asd_ha_struct *asd_ha) | ||
281 | { | ||
282 | u32 ctxmemsize = asd_read_reg_dword(asd_ha, LmMnINT(0,0)) & CTXMEMSIZE; | ||
283 | return ctxmemsize ? 8192 : 4096; | ||
284 | } | ||
285 | |||
286 | static inline void asd_disable_ints(struct asd_ha_struct *asd_ha) | ||
287 | { | ||
288 | asd_write_reg_dword(asd_ha, CHIMINTEN, RST_CHIMINTEN); | ||
289 | } | ||
290 | |||
291 | static inline void asd_enable_ints(struct asd_ha_struct *asd_ha) | ||
292 | { | ||
293 | /* Enable COM SAS interrupt on errors, COMSTAT */ | ||
294 | asd_write_reg_dword(asd_ha, COMSTATEN, | ||
295 | EN_CSBUFPERR | EN_CSERR | EN_OVLYERR); | ||
296 | /* Enable DCH SAS CFIFTOERR */ | ||
297 | asd_write_reg_dword(asd_ha, DCHSTATUS, EN_CFIFTOERR); | ||
298 | /* Enable Host Device interrupts */ | ||
299 | asd_write_reg_dword(asd_ha, CHIMINTEN, SET_CHIMINTEN); | ||
300 | } | ||
301 | |||
302 | #endif | ||
diff --git a/drivers/scsi/aic94xx/aic94xx_reg_def.h b/drivers/scsi/aic94xx/aic94xx_reg_def.h new file mode 100644 index 000000000000..b79f45f3ad47 --- /dev/null +++ b/drivers/scsi/aic94xx/aic94xx_reg_def.h | |||
@@ -0,0 +1,2398 @@ | |||
1 | /* | ||
2 | * Aic94xx SAS/SATA driver hardware registers defintions. | ||
3 | * | ||
4 | * Copyright (C) 2004 Adaptec, Inc. All rights reserved. | ||
5 | * Copyright (C) 2004 David Chaw <david_chaw@adaptec.com> | ||
6 | * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> | ||
7 | * | ||
8 | * Luben Tuikov: Some register value updates to make it work with the window | ||
9 | * agnostic register r/w functions. Some register corrections, sizes, | ||
10 | * etc. | ||
11 | * | ||
12 | * This file is licensed under GPLv2. | ||
13 | * | ||
14 | * This file is part of the aic94xx driver. | ||
15 | * | ||
16 | * The aic94xx driver is free software; you can redistribute it and/or | ||
17 | * modify it under the terms of the GNU General Public License as | ||
18 | * published by the Free Software Foundation; version 2 of the | ||
19 | * License. | ||
20 | * | ||
21 | * The aic94xx driver is distributed in the hope that it will be useful, | ||
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
24 | * General Public License for more details. | ||
25 | * | ||
26 | * You should have received a copy of the GNU General Public License | ||
27 | * along with the aic94xx driver; if not, write to the Free Software | ||
28 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
29 | * | ||
30 | * $Id: //depot/aic94xx/aic94xx_reg_def.h#27 $ | ||
31 | * | ||
32 | */ | ||
33 | |||
34 | #ifndef _ADP94XX_REG_DEF_H_ | ||
35 | #define _ADP94XX_REG_DEF_H_ | ||
36 | |||
37 | /* | ||
38 | * Common definitions. | ||
39 | */ | ||
40 | #define CSEQ_MODE_PAGE_SIZE 0x200 /* CSEQ mode page size */ | ||
41 | #define LmSEQ_MODE_PAGE_SIZE 0x200 /* LmSEQ mode page size */ | ||
42 | #define LmSEQ_HOST_REG_SIZE 0x4000 /* LmSEQ Host Register size */ | ||
43 | |||
44 | /********************* COM_SAS registers definition *************************/ | ||
45 | |||
46 | /* The base is REG_BASE_ADDR, defined in aic94xx_reg.h. | ||
47 | */ | ||
48 | |||
49 | /* | ||
50 | * CHIM Registers, Address Range : (0x00-0xFF) | ||
51 | */ | ||
52 | #define COMBIST (REG_BASE_ADDR + 0x00) | ||
53 | |||
54 | /* bits 31:24 */ | ||
55 | #define L7BLKRST 0x80000000 | ||
56 | #define L6BLKRST 0x40000000 | ||
57 | #define L5BLKRST 0x20000000 | ||
58 | #define L4BLKRST 0x10000000 | ||
59 | #define L3BLKRST 0x08000000 | ||
60 | #define L2BLKRST 0x04000000 | ||
61 | #define L1BLKRST 0x02000000 | ||
62 | #define L0BLKRST 0x01000000 | ||
63 | #define LmBLKRST 0xFF000000 | ||
64 | #define LmBLKRST_COMBIST(phyid) (1 << (24 + phyid)) | ||
65 | |||
66 | #define OCMBLKRST 0x00400000 | ||
67 | #define CTXMEMBLKRST 0x00200000 | ||
68 | #define CSEQBLKRST 0x00100000 | ||
69 | #define EXSIBLKRST 0x00040000 | ||
70 | #define DPIBLKRST 0x00020000 | ||
71 | #define DFIFBLKRST 0x00010000 | ||
72 | #define HARDRST 0x00000200 | ||
73 | #define COMBLKRST 0x00000100 | ||
74 | #define FRCDFPERR 0x00000080 | ||
75 | #define FRCCIOPERR 0x00000020 | ||
76 | #define FRCBISTERR 0x00000010 | ||
77 | #define COMBISTEN 0x00000004 | ||
78 | #define COMBISTDONE 0x00000002 /* ro */ | ||
79 | #define COMBISTFAIL 0x00000001 /* ro */ | ||
80 | |||
81 | #define COMSTAT (REG_BASE_ADDR + 0x04) | ||
82 | |||
83 | #define REQMBXREAD 0x00000040 | ||
84 | #define RSPMBXAVAIL 0x00000020 | ||
85 | #define CSBUFPERR 0x00000008 | ||
86 | #define OVLYERR 0x00000004 | ||
87 | #define CSERR 0x00000002 | ||
88 | #define OVLYDMADONE 0x00000001 | ||
89 | |||
90 | #define COMSTAT_MASK (REQMBXREAD | RSPMBXAVAIL | \ | ||
91 | CSBUFPERR | OVLYERR | CSERR |\ | ||
92 | OVLYDMADONE) | ||
93 | |||
94 | #define COMSTATEN (REG_BASE_ADDR + 0x08) | ||
95 | |||
96 | #define EN_REQMBXREAD 0x00000040 | ||
97 | #define EN_RSPMBXAVAIL 0x00000020 | ||
98 | #define EN_CSBUFPERR 0x00000008 | ||
99 | #define EN_OVLYERR 0x00000004 | ||
100 | #define EN_CSERR 0x00000002 | ||
101 | #define EN_OVLYDONE 0x00000001 | ||
102 | |||
103 | #define SCBPRO (REG_BASE_ADDR + 0x0C) | ||
104 | |||
105 | #define SCBCONS_MASK 0xFFFF0000 | ||
106 | #define SCBPRO_MASK 0x0000FFFF | ||
107 | |||
108 | #define CHIMREQMBX (REG_BASE_ADDR + 0x10) | ||
109 | |||
110 | #define CHIMRSPMBX (REG_BASE_ADDR + 0x14) | ||
111 | |||
112 | #define CHIMINT (REG_BASE_ADDR + 0x18) | ||
113 | |||
114 | #define EXT_INT0 0x00000800 | ||
115 | #define EXT_INT1 0x00000400 | ||
116 | #define PORRSTDET 0x00000200 | ||
117 | #define HARDRSTDET 0x00000100 | ||
118 | #define DLAVAILQ 0x00000080 /* ro */ | ||
119 | #define HOSTERR 0x00000040 | ||
120 | #define INITERR 0x00000020 | ||
121 | #define DEVINT 0x00000010 | ||
122 | #define COMINT 0x00000008 | ||
123 | #define DEVTIMER2 0x00000004 | ||
124 | #define DEVTIMER1 0x00000002 | ||
125 | #define DLAVAIL 0x00000001 | ||
126 | |||
127 | #define CHIMINT_MASK (HOSTERR | INITERR | DEVINT | COMINT |\ | ||
128 | DEVTIMER2 | DEVTIMER1 | DLAVAIL) | ||
129 | |||
130 | #define DEVEXCEPT_MASK (HOSTERR | INITERR | DEVINT | COMINT) | ||
131 | |||
132 | #define CHIMINTEN (REG_BASE_ADDR + 0x1C) | ||
133 | |||
134 | #define RST_EN_EXT_INT1 0x01000000 | ||
135 | #define RST_EN_EXT_INT0 0x00800000 | ||
136 | #define RST_EN_HOSTERR 0x00400000 | ||
137 | #define RST_EN_INITERR 0x00200000 | ||
138 | #define RST_EN_DEVINT 0x00100000 | ||
139 | #define RST_EN_COMINT 0x00080000 | ||
140 | #define RST_EN_DEVTIMER2 0x00040000 | ||
141 | #define RST_EN_DEVTIMER1 0x00020000 | ||
142 | #define RST_EN_DLAVAIL 0x00010000 | ||
143 | #define SET_EN_EXT_INT1 0x00000100 | ||
144 | #define SET_EN_EXT_INT0 0x00000080 | ||
145 | #define SET_EN_HOSTERR 0x00000040 | ||
146 | #define SET_EN_INITERR 0x00000020 | ||
147 | #define SET_EN_DEVINT 0x00000010 | ||
148 | #define SET_EN_COMINT 0x00000008 | ||
149 | #define SET_EN_DEVTIMER2 0x00000004 | ||
150 | #define SET_EN_DEVTIMER1 0x00000002 | ||
151 | #define SET_EN_DLAVAIL 0x00000001 | ||
152 | |||
153 | #define RST_CHIMINTEN (RST_EN_HOSTERR | RST_EN_INITERR | \ | ||
154 | RST_EN_DEVINT | RST_EN_COMINT | \ | ||
155 | RST_EN_DEVTIMER2 | RST_EN_DEVTIMER1 |\ | ||
156 | RST_EN_DLAVAIL) | ||
157 | |||
158 | #define SET_CHIMINTEN (SET_EN_HOSTERR | SET_EN_INITERR |\ | ||
159 | SET_EN_DEVINT | SET_EN_COMINT |\ | ||
160 | SET_EN_DLAVAIL) | ||
161 | |||
162 | #define OVLYDMACTL (REG_BASE_ADDR + 0x20) | ||
163 | |||
164 | #define OVLYADR_MASK 0x07FF0000 | ||
165 | #define OVLYLSEQ_MASK 0x0000FF00 | ||
166 | #define OVLYCSEQ 0x00000080 | ||
167 | #define OVLYHALTERR 0x00000040 | ||
168 | #define PIOCMODE 0x00000020 | ||
169 | #define RESETOVLYDMA 0x00000008 /* wo */ | ||
170 | #define STARTOVLYDMA 0x00000004 | ||
171 | #define STOPOVLYDMA 0x00000002 /* wo */ | ||
172 | #define OVLYDMAACT 0x00000001 /* ro */ | ||
173 | |||
174 | #define OVLYDMACNT (REG_BASE_ADDR + 0x24) | ||
175 | |||
176 | #define OVLYDOMAIN1 0x20000000 /* ro */ | ||
177 | #define OVLYDOMAIN0 0x10000000 | ||
178 | #define OVLYBUFADR_MASK 0x007F0000 | ||
179 | #define OVLYDMACNT_MASK 0x00003FFF | ||
180 | |||
181 | #define OVLYDMAADR (REG_BASE_ADDR + 0x28) | ||
182 | |||
183 | #define DMAERR (REG_BASE_ADDR + 0x30) | ||
184 | |||
185 | #define OVLYERRSTAT_MASK 0x0000FF00 /* ro */ | ||
186 | #define CSERRSTAT_MASK 0x000000FF /* ro */ | ||
187 | |||
188 | #define SPIODATA (REG_BASE_ADDR + 0x34) | ||
189 | |||
190 | /* 0x38 - 0x3C are reserved */ | ||
191 | |||
192 | #define T1CNTRLR (REG_BASE_ADDR + 0x40) | ||
193 | |||
194 | #define T1DONE 0x00010000 /* ro */ | ||
195 | #define TIMER64 0x00000400 | ||
196 | #define T1ENABLE 0x00000200 | ||
197 | #define T1RELOAD 0x00000100 | ||
198 | #define T1PRESCALER_MASK 0x00000003 | ||
199 | |||
200 | #define T1CMPR (REG_BASE_ADDR + 0x44) | ||
201 | |||
202 | #define T1CNTR (REG_BASE_ADDR + 0x48) | ||
203 | |||
204 | #define T2CNTRLR (REG_BASE_ADDR + 0x4C) | ||
205 | |||
206 | #define T2DONE 0x00010000 /* ro */ | ||
207 | #define T2ENABLE 0x00000200 | ||
208 | #define T2RELOAD 0x00000100 | ||
209 | #define T2PRESCALER_MASK 0x00000003 | ||
210 | |||
211 | #define T2CMPR (REG_BASE_ADDR + 0x50) | ||
212 | |||
213 | #define T2CNTR (REG_BASE_ADDR + 0x54) | ||
214 | |||
215 | /* 0x58h - 0xFCh are reserved */ | ||
216 | |||
217 | /* | ||
218 | * DCH_SAS Registers, Address Range : (0x800-0xFFF) | ||
219 | */ | ||
220 | #define CMDCTXBASE (REG_BASE_ADDR + 0x800) | ||
221 | |||
222 | #define DEVCTXBASE (REG_BASE_ADDR + 0x808) | ||
223 | |||
224 | #define CTXDOMAIN (REG_BASE_ADDR + 0x810) | ||
225 | |||
226 | #define DEVCTXDOMAIN1 0x00000008 /* ro */ | ||
227 | #define DEVCTXDOMAIN0 0x00000004 | ||
228 | #define CMDCTXDOMAIN1 0x00000002 /* ro */ | ||
229 | #define CMDCTXDOMAIN0 0x00000001 | ||
230 | |||
231 | #define DCHCTL (REG_BASE_ADDR + 0x814) | ||
232 | |||
233 | #define OCMBISTREPAIR 0x00080000 | ||
234 | #define OCMBISTEN 0x00040000 | ||
235 | #define OCMBISTDN 0x00020000 /* ro */ | ||
236 | #define OCMBISTFAIL 0x00010000 /* ro */ | ||
237 | #define DDBBISTEN 0x00004000 | ||
238 | #define DDBBISTDN 0x00002000 /* ro */ | ||
239 | #define DDBBISTFAIL 0x00001000 /* ro */ | ||
240 | #define SCBBISTEN 0x00000400 | ||
241 | #define SCBBISTDN 0x00000200 /* ro */ | ||
242 | #define SCBBISTFAIL 0x00000100 /* ro */ | ||
243 | |||
244 | #define MEMSEL_MASK 0x000000E0 | ||
245 | #define MEMSEL_CCM_LSEQ 0x00000000 | ||
246 | #define MEMSEL_CCM_IOP 0x00000020 | ||
247 | #define MEMSEL_CCM_SASCTL 0x00000040 | ||
248 | #define MEMSEL_DCM_LSEQ 0x00000060 | ||
249 | #define MEMSEL_DCM_IOP 0x00000080 | ||
250 | #define MEMSEL_OCM 0x000000A0 | ||
251 | |||
252 | #define FRCERR 0x00000010 | ||
253 | #define AUTORLS 0x00000001 | ||
254 | |||
255 | #define DCHREVISION (REG_BASE_ADDR + 0x818) | ||
256 | |||
257 | #define DCHREVISION_MASK 0x000000FF | ||
258 | |||
259 | #define DCHSTATUS (REG_BASE_ADDR + 0x81C) | ||
260 | |||
261 | #define EN_CFIFTOERR 0x00020000 | ||
262 | #define CFIFTOERR 0x00000200 | ||
263 | #define CSEQINT 0x00000100 /* ro */ | ||
264 | #define LSEQ7INT 0x00000080 /* ro */ | ||
265 | #define LSEQ6INT 0x00000040 /* ro */ | ||
266 | #define LSEQ5INT 0x00000020 /* ro */ | ||
267 | #define LSEQ4INT 0x00000010 /* ro */ | ||
268 | #define LSEQ3INT 0x00000008 /* ro */ | ||
269 | #define LSEQ2INT 0x00000004 /* ro */ | ||
270 | #define LSEQ1INT 0x00000002 /* ro */ | ||
271 | #define LSEQ0INT 0x00000001 /* ro */ | ||
272 | |||
273 | #define LSEQINT_MASK (LSEQ7INT | LSEQ6INT | LSEQ5INT |\ | ||
274 | LSEQ4INT | LSEQ3INT | LSEQ2INT |\ | ||
275 | LSEQ1INT | LSEQ0INT) | ||
276 | |||
277 | #define DCHDFIFDEBUG (REG_BASE_ADDR + 0x820) | ||
278 | #define ENFAIRMST 0x00FF0000 | ||
279 | #define DISWRMST9 0x00000200 | ||
280 | #define DISWRMST8 0x00000100 | ||
281 | #define DISRDMST 0x000000FF | ||
282 | |||
283 | #define ATOMICSTATCTL (REG_BASE_ADDR + 0x824) | ||
284 | /* 8 bit wide */ | ||
285 | #define AUTOINC 0x80 | ||
286 | #define ATOMICERR 0x04 | ||
287 | #define ATOMICWIN 0x02 | ||
288 | #define ATOMICDONE 0x01 | ||
289 | |||
290 | |||
291 | #define ALTCIOADR (REG_BASE_ADDR + 0x828) | ||
292 | /* 16 bit; bits 8:0 define CIO addr space of CSEQ */ | ||
293 | |||
294 | #define ASCBPTR (REG_BASE_ADDR + 0x82C) | ||
295 | /* 16 bit wide */ | ||
296 | |||
297 | #define ADDBPTR (REG_BASE_ADDR + 0x82E) | ||
298 | /* 16 bit wide */ | ||
299 | |||
300 | #define ANEWDATA (REG_BASE_ADDR + 0x830) | ||
301 | /* 16 bit */ | ||
302 | |||
303 | #define AOLDDATA (REG_BASE_ADDR + 0x834) | ||
304 | /* 16 bit */ | ||
305 | |||
306 | #define CTXACCESS (REG_BASE_ADDR + 0x838) | ||
307 | /* 32 bit */ | ||
308 | |||
309 | /* 0x83Ch - 0xFFCh are reserved */ | ||
310 | |||
311 | /* | ||
312 | * ARP2 External Processor Registers, Address Range : (0x00-0x1F) | ||
313 | */ | ||
314 | #define ARP2CTL 0x00 | ||
315 | |||
316 | #define FRCSCRPERR 0x00040000 | ||
317 | #define FRCARP2PERR 0x00020000 | ||
318 | #define FRCARP2ILLOPC 0x00010000 | ||
319 | #define ENWAITTO 0x00008000 | ||
320 | #define PERRORDIS 0x00004000 | ||
321 | #define FAILDIS 0x00002000 | ||
322 | #define CIOPERRDIS 0x00001000 | ||
323 | #define BREAKEN3 0x00000800 | ||
324 | #define BREAKEN2 0x00000400 | ||
325 | #define BREAKEN1 0x00000200 | ||
326 | #define BREAKEN0 0x00000100 | ||
327 | #define EPAUSE 0x00000008 | ||
328 | #define PAUSED 0x00000004 /* ro */ | ||
329 | #define STEP 0x00000002 | ||
330 | #define ARP2RESET 0x00000001 /* wo */ | ||
331 | |||
332 | #define ARP2INT 0x04 | ||
333 | |||
334 | #define HALTCODE_MASK 0x00FF0000 /* ro */ | ||
335 | #define ARP2WAITTO 0x00000100 | ||
336 | #define ARP2HALTC 0x00000080 | ||
337 | #define ARP2ILLOPC 0x00000040 | ||
338 | #define ARP2PERR 0x00000020 | ||
339 | #define ARP2CIOPERR 0x00000010 | ||
340 | #define ARP2BREAK3 0x00000008 | ||
341 | #define ARP2BREAK2 0x00000004 | ||
342 | #define ARP2BREAK1 0x00000002 | ||
343 | #define ARP2BREAK0 0x00000001 | ||
344 | |||
345 | #define ARP2INTEN 0x08 | ||
346 | |||
347 | #define EN_ARP2WAITTO 0x00000100 | ||
348 | #define EN_ARP2HALTC 0x00000080 | ||
349 | #define EN_ARP2ILLOPC 0x00000040 | ||
350 | #define EN_ARP2PERR 0x00000020 | ||
351 | #define EN_ARP2CIOPERR 0x00000010 | ||
352 | #define EN_ARP2BREAK3 0x00000008 | ||
353 | #define EN_ARP2BREAK2 0x00000004 | ||
354 | #define EN_ARP2BREAK1 0x00000002 | ||
355 | #define EN_ARP2BREAK0 0x00000001 | ||
356 | |||
357 | #define ARP2BREAKADR01 0x0C | ||
358 | |||
359 | #define BREAKADR1_MASK 0x0FFF0000 | ||
360 | #define BREAKADR0_MASK 0x00000FFF | ||
361 | |||
362 | #define ARP2BREAKADR23 0x10 | ||
363 | |||
364 | #define BREAKADR3_MASK 0x0FFF0000 | ||
365 | #define BREAKADR2_MASK 0x00000FFF | ||
366 | |||
367 | /* 0x14h - 0x1Ch are reserved */ | ||
368 | |||
369 | /* | ||
370 | * ARP2 Registers, Address Range : (0x00-0x1F) | ||
371 | * The definitions have the same address offset for CSEQ and LmSEQ | ||
372 | * CIO Bus Registers. | ||
373 | */ | ||
374 | #define MODEPTR 0x00 | ||
375 | |||
376 | #define DSTMODE 0xF0 | ||
377 | #define SRCMODE 0x0F | ||
378 | |||
379 | #define ALTMODE 0x01 | ||
380 | |||
381 | #define ALTDMODE 0xF0 | ||
382 | #define ALTSMODE 0x0F | ||
383 | |||
384 | #define ATOMICXCHG 0x02 | ||
385 | |||
386 | #define FLAG 0x04 | ||
387 | |||
388 | #define INTCODE_MASK 0xF0 | ||
389 | #define ALTMODEV2 0x04 | ||
390 | #define CARRY_INT 0x02 | ||
391 | #define CARRY 0x01 | ||
392 | |||
393 | #define ARP2INTCTL 0x05 | ||
394 | |||
395 | #define PAUSEDIS 0x80 | ||
396 | #define RSTINTCTL 0x40 | ||
397 | #define POPALTMODE 0x08 | ||
398 | #define ALTMODEV 0x04 | ||
399 | #define INTMASK 0x02 | ||
400 | #define IRET 0x01 | ||
401 | |||
402 | #define STACK 0x06 | ||
403 | |||
404 | #define FUNCTION1 0x07 | ||
405 | |||
406 | #define PRGMCNT 0x08 | ||
407 | |||
408 | #define ACCUM 0x0A | ||
409 | |||
410 | #define SINDEX 0x0C | ||
411 | |||
412 | #define DINDEX 0x0E | ||
413 | |||
414 | #define ALLONES 0x10 | ||
415 | |||
416 | #define ALLZEROS 0x11 | ||
417 | |||
418 | #define SINDIR 0x12 | ||
419 | |||
420 | #define DINDIR 0x13 | ||
421 | |||
422 | #define JUMLDIR 0x14 | ||
423 | |||
424 | #define ARP2HALTCODE 0x15 | ||
425 | |||
426 | #define CURRADDR 0x16 | ||
427 | |||
428 | #define LASTADDR 0x18 | ||
429 | |||
430 | #define NXTLADDR 0x1A | ||
431 | |||
432 | #define DBGPORTPTR 0x1C | ||
433 | |||
434 | #define DBGPORT 0x1D | ||
435 | |||
436 | /* | ||
437 | * CIO Registers. | ||
438 | * The definitions have the same address offset for CSEQ and LmSEQ | ||
439 | * CIO Bus Registers. | ||
440 | */ | ||
441 | #define MnSCBPTR 0x20 | ||
442 | |||
443 | #define MnDDBPTR 0x22 | ||
444 | |||
445 | #define SCRATCHPAGE 0x24 | ||
446 | |||
447 | #define MnSCRATCHPAGE 0x25 | ||
448 | |||
449 | #define SCRATCHPAGESV 0x26 | ||
450 | |||
451 | #define MnSCRATCHPAGESV 0x27 | ||
452 | |||
453 | #define MnDMAERRS 0x46 | ||
454 | |||
455 | #define MnSGDMAERRS 0x47 | ||
456 | |||
457 | #define MnSGBUF 0x53 | ||
458 | |||
459 | #define MnSGDMASTAT 0x5b | ||
460 | |||
461 | #define MnDDMACTL 0x5c /* RAZOR.rspec.fm rev 1.5 is wrong */ | ||
462 | |||
463 | #define MnDDMASTAT 0x5d /* RAZOR.rspec.fm rev 1.5 is wrong */ | ||
464 | |||
465 | #define MnDDMAMODE 0x5e /* RAZOR.rspec.fm rev 1.5 is wrong */ | ||
466 | |||
467 | #define MnDMAENG 0x60 | ||
468 | |||
469 | #define MnPIPECTL 0x61 | ||
470 | |||
471 | #define MnSGBADR 0x65 | ||
472 | |||
473 | #define MnSCB_SITE 0x100 | ||
474 | |||
475 | #define MnDDB_SITE 0x180 | ||
476 | |||
477 | /* | ||
478 | * The common definitions below have the same address offset for both | ||
479 | * CSEQ and LmSEQ. | ||
480 | */ | ||
481 | #define BISTCTL0 0x4C | ||
482 | |||
483 | #define BISTCTL1 0x50 | ||
484 | |||
485 | #define MAPPEDSCR 0x800 | ||
486 | |||
487 | /* | ||
488 | * CSEQ Host Register, Address Range : (0x000-0xFFC) | ||
489 | */ | ||
490 | #define CSEQ_HOST_REG_BASE_ADR 0xB8001000 | ||
491 | |||
492 | #define CARP2CTL (CSEQ_HOST_REG_BASE_ADR + ARP2CTL) | ||
493 | |||
494 | #define CARP2INT (CSEQ_HOST_REG_BASE_ADR + ARP2INT) | ||
495 | |||
496 | #define CARP2INTEN (CSEQ_HOST_REG_BASE_ADR + ARP2INTEN) | ||
497 | |||
498 | #define CARP2BREAKADR01 (CSEQ_HOST_REG_BASE_ADR+ARP2BREAKADR01) | ||
499 | |||
500 | #define CARP2BREAKADR23 (CSEQ_HOST_REG_BASE_ADR+ARP2BREAKADR23) | ||
501 | |||
502 | #define CBISTCTL (CSEQ_HOST_REG_BASE_ADR + BISTCTL1) | ||
503 | |||
504 | #define CSEQRAMBISTEN 0x00000040 | ||
505 | #define CSEQRAMBISTDN 0x00000020 /* ro */ | ||
506 | #define CSEQRAMBISTFAIL 0x00000010 /* ro */ | ||
507 | #define CSEQSCRBISTEN 0x00000004 | ||
508 | #define CSEQSCRBISTDN 0x00000002 /* ro */ | ||
509 | #define CSEQSCRBISTFAIL 0x00000001 /* ro */ | ||
510 | |||
511 | #define CMAPPEDSCR (CSEQ_HOST_REG_BASE_ADR + MAPPEDSCR) | ||
512 | |||
513 | /* | ||
514 | * CSEQ CIO Bus Registers, Address Range : (0x0000-0x1FFC) | ||
515 | * 16 modes, each mode is 512 bytes. | ||
516 | * Unless specified, the register should valid for all modes. | ||
517 | */ | ||
518 | #define CSEQ_CIO_REG_BASE_ADR REG_BASE_ADDR_CSEQCIO | ||
519 | |||
520 | #define CSEQm_CIO_REG(Mode, Reg) \ | ||
521 | (CSEQ_CIO_REG_BASE_ADR + \ | ||
522 | ((u32) (Mode) * CSEQ_MODE_PAGE_SIZE) + (u32) (Reg)) | ||
523 | |||
524 | #define CMODEPTR (CSEQ_CIO_REG_BASE_ADR + MODEPTR) | ||
525 | |||
526 | #define CALTMODE (CSEQ_CIO_REG_BASE_ADR + ALTMODE) | ||
527 | |||
528 | #define CATOMICXCHG (CSEQ_CIO_REG_BASE_ADR + ATOMICXCHG) | ||
529 | |||
530 | #define CFLAG (CSEQ_CIO_REG_BASE_ADR + FLAG) | ||
531 | |||
532 | #define CARP2INTCTL (CSEQ_CIO_REG_BASE_ADR + ARP2INTCTL) | ||
533 | |||
534 | #define CSTACK (CSEQ_CIO_REG_BASE_ADR + STACK) | ||
535 | |||
536 | #define CFUNCTION1 (CSEQ_CIO_REG_BASE_ADR + FUNCTION1) | ||
537 | |||
538 | #define CPRGMCNT (CSEQ_CIO_REG_BASE_ADR + PRGMCNT) | ||
539 | |||
540 | #define CACCUM (CSEQ_CIO_REG_BASE_ADR + ACCUM) | ||
541 | |||
542 | #define CSINDEX (CSEQ_CIO_REG_BASE_ADR + SINDEX) | ||
543 | |||
544 | #define CDINDEX (CSEQ_CIO_REG_BASE_ADR + DINDEX) | ||
545 | |||
546 | #define CALLONES (CSEQ_CIO_REG_BASE_ADR + ALLONES) | ||
547 | |||
548 | #define CALLZEROS (CSEQ_CIO_REG_BASE_ADR + ALLZEROS) | ||
549 | |||
550 | #define CSINDIR (CSEQ_CIO_REG_BASE_ADR + SINDIR) | ||
551 | |||
552 | #define CDINDIR (CSEQ_CIO_REG_BASE_ADR + DINDIR) | ||
553 | |||
554 | #define CJUMLDIR (CSEQ_CIO_REG_BASE_ADR + JUMLDIR) | ||
555 | |||
556 | #define CARP2HALTCODE (CSEQ_CIO_REG_BASE_ADR + ARP2HALTCODE) | ||
557 | |||
558 | #define CCURRADDR (CSEQ_CIO_REG_BASE_ADR + CURRADDR) | ||
559 | |||
560 | #define CLASTADDR (CSEQ_CIO_REG_BASE_ADR + LASTADDR) | ||
561 | |||
562 | #define CNXTLADDR (CSEQ_CIO_REG_BASE_ADR + NXTLADDR) | ||
563 | |||
564 | #define CDBGPORTPTR (CSEQ_CIO_REG_BASE_ADR + DBGPORTPTR) | ||
565 | |||
566 | #define CDBGPORT (CSEQ_CIO_REG_BASE_ADR + DBGPORT) | ||
567 | |||
568 | #define CSCRATCHPAGE (CSEQ_CIO_REG_BASE_ADR + SCRATCHPAGE) | ||
569 | |||
570 | #define CMnSCBPTR(Mode) CSEQm_CIO_REG(Mode, MnSCBPTR) | ||
571 | |||
572 | #define CMnDDBPTR(Mode) CSEQm_CIO_REG(Mode, MnDDBPTR) | ||
573 | |||
574 | #define CMnSCRATCHPAGE(Mode) CSEQm_CIO_REG(Mode, MnSCRATCHPAGE) | ||
575 | |||
576 | #define CLINKCON (CSEQ_CIO_REG_BASE_ADR + 0x28) | ||
577 | |||
578 | #define CCIOAACESS (CSEQ_CIO_REG_BASE_ADR + 0x2C) | ||
579 | |||
580 | /* mode 0-7 */ | ||
581 | #define MnREQMBX 0x30 | ||
582 | #define CMnREQMBX(Mode) CSEQm_CIO_REG(Mode, 0x30) | ||
583 | |||
584 | /* mode 8 */ | ||
585 | #define CSEQCON CSEQm_CIO_REG(8, 0x30) | ||
586 | |||
587 | /* mode 0-7 */ | ||
588 | #define MnRSPMBX 0x34 | ||
589 | #define CMnRSPMBX(Mode) CSEQm_CIO_REG(Mode, 0x34) | ||
590 | |||
591 | /* mode 8 */ | ||
592 | #define CSEQCOMCTL CSEQm_CIO_REG(8, 0x34) | ||
593 | |||
594 | /* mode 8 */ | ||
595 | #define CSEQCOMSTAT CSEQm_CIO_REG(8, 0x35) | ||
596 | |||
597 | /* mode 8 */ | ||
598 | #define CSEQCOMINTEN CSEQm_CIO_REG(8, 0x36) | ||
599 | |||
600 | /* mode 8 */ | ||
601 | #define CSEQCOMDMACTL CSEQm_CIO_REG(8, 0x37) | ||
602 | |||
603 | #define CSHALTERR 0x10 | ||
604 | #define RESETCSDMA 0x08 /* wo */ | ||
605 | #define STARTCSDMA 0x04 | ||
606 | #define STOPCSDMA 0x02 /* wo */ | ||
607 | #define CSDMAACT 0x01 /* ro */ | ||
608 | |||
609 | /* mode 0-7 */ | ||
610 | #define MnINT 0x38 | ||
611 | #define CMnINT(Mode) CSEQm_CIO_REG(Mode, 0x38) | ||
612 | |||
613 | #define CMnREQMBXE 0x02 | ||
614 | #define CMnRSPMBXF 0x01 | ||
615 | #define CMnINT_MASK 0x00000003 | ||
616 | |||
617 | /* mode 8 */ | ||
618 | #define CSEQREQMBX CSEQm_CIO_REG(8, 0x38) | ||
619 | |||
620 | /* mode 0-7 */ | ||
621 | #define MnINTEN 0x3C | ||
622 | #define CMnINTEN(Mode) CSEQm_CIO_REG(Mode, 0x3C) | ||
623 | |||
624 | #define EN_CMnRSPMBXF 0x01 | ||
625 | |||
626 | /* mode 8 */ | ||
627 | #define CSEQRSPMBX CSEQm_CIO_REG(8, 0x3C) | ||
628 | |||
629 | /* mode 8 */ | ||
630 | #define CSDMAADR CSEQm_CIO_REG(8, 0x40) | ||
631 | |||
632 | /* mode 8 */ | ||
633 | #define CSDMACNT CSEQm_CIO_REG(8, 0x48) | ||
634 | |||
635 | /* mode 8 */ | ||
636 | #define CSEQDLCTL CSEQm_CIO_REG(8, 0x4D) | ||
637 | |||
638 | #define DONELISTEND 0x10 | ||
639 | #define DONELISTSIZE_MASK 0x0F | ||
640 | #define DONELISTSIZE_8ELEM 0x01 | ||
641 | #define DONELISTSIZE_16ELEM 0x02 | ||
642 | #define DONELISTSIZE_32ELEM 0x03 | ||
643 | #define DONELISTSIZE_64ELEM 0x04 | ||
644 | #define DONELISTSIZE_128ELEM 0x05 | ||
645 | #define DONELISTSIZE_256ELEM 0x06 | ||
646 | #define DONELISTSIZE_512ELEM 0x07 | ||
647 | #define DONELISTSIZE_1024ELEM 0x08 | ||
648 | #define DONELISTSIZE_2048ELEM 0x09 | ||
649 | #define DONELISTSIZE_4096ELEM 0x0A | ||
650 | #define DONELISTSIZE_8192ELEM 0x0B | ||
651 | #define DONELISTSIZE_16384ELEM 0x0C | ||
652 | |||
653 | /* mode 8 */ | ||
654 | #define CSEQDLOFFS CSEQm_CIO_REG(8, 0x4E) | ||
655 | |||
656 | /* mode 11 */ | ||
657 | #define CM11INTVEC0 CSEQm_CIO_REG(11, 0x50) | ||
658 | |||
659 | /* mode 11 */ | ||
660 | #define CM11INTVEC1 CSEQm_CIO_REG(11, 0x52) | ||
661 | |||
662 | /* mode 11 */ | ||
663 | #define CM11INTVEC2 CSEQm_CIO_REG(11, 0x54) | ||
664 | |||
665 | #define CCONMSK (CSEQ_CIO_REG_BASE_ADR + 0x60) | ||
666 | |||
667 | #define CCONEXIST (CSEQ_CIO_REG_BASE_ADR + 0x61) | ||
668 | |||
669 | #define CCONMODE (CSEQ_CIO_REG_BASE_ADR + 0x62) | ||
670 | |||
671 | #define CTIMERCALC (CSEQ_CIO_REG_BASE_ADR + 0x64) | ||
672 | |||
673 | #define CINTDIS (CSEQ_CIO_REG_BASE_ADR + 0x68) | ||
674 | |||
675 | /* mode 8, 32x32 bits, 128 bytes of mapped buffer */ | ||
676 | #define CSBUFFER CSEQm_CIO_REG(8, 0x80) | ||
677 | |||
678 | #define CSCRATCH (CSEQ_CIO_REG_BASE_ADR + 0x1C0) | ||
679 | |||
680 | /* mode 0-8 */ | ||
681 | #define CMnSCRATCH(Mode) CSEQm_CIO_REG(Mode, 0x1E0) | ||
682 | |||
683 | /* | ||
684 | * CSEQ Mapped Instruction RAM Page, Address Range : (0x0000-0x1FFC) | ||
685 | */ | ||
686 | #define CSEQ_RAM_REG_BASE_ADR 0xB8004000 | ||
687 | |||
688 | /* | ||
689 | * The common definitions below have the same address offset for all the Link | ||
690 | * sequencers. | ||
691 | */ | ||
692 | #define MODECTL 0x40 | ||
693 | |||
694 | #define DBGMODE 0x44 | ||
695 | |||
696 | #define CONTROL 0x48 | ||
697 | #define LEDTIMER 0x00010000 | ||
698 | #define LEDTIMERS_10us 0x00000000 | ||
699 | #define LEDTIMERS_1ms 0x00000800 | ||
700 | #define LEDTIMERS_100ms 0x00001000 | ||
701 | #define LEDMODE_TXRX 0x00000000 | ||
702 | #define LEDMODE_CONNECTED 0x00000200 | ||
703 | #define LEDPOL 0x00000100 | ||
704 | |||
705 | #define LSEQRAM 0x1000 | ||
706 | |||
707 | /* | ||
708 | * LmSEQ Host Registers, Address Range : (0x0000-0x3FFC) | ||
709 | */ | ||
710 | #define LSEQ0_HOST_REG_BASE_ADR 0xB8020000 | ||
711 | #define LSEQ1_HOST_REG_BASE_ADR 0xB8024000 | ||
712 | #define LSEQ2_HOST_REG_BASE_ADR 0xB8028000 | ||
713 | #define LSEQ3_HOST_REG_BASE_ADR 0xB802C000 | ||
714 | #define LSEQ4_HOST_REG_BASE_ADR 0xB8030000 | ||
715 | #define LSEQ5_HOST_REG_BASE_ADR 0xB8034000 | ||
716 | #define LSEQ6_HOST_REG_BASE_ADR 0xB8038000 | ||
717 | #define LSEQ7_HOST_REG_BASE_ADR 0xB803C000 | ||
718 | |||
719 | #define LmARP2CTL(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \ | ||
720 | ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \ | ||
721 | ARP2CTL) | ||
722 | |||
723 | #define LmARP2INT(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \ | ||
724 | ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \ | ||
725 | ARP2INT) | ||
726 | |||
727 | #define LmARP2INTEN(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \ | ||
728 | ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \ | ||
729 | ARP2INTEN) | ||
730 | |||
731 | #define LmDBGMODE(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \ | ||
732 | ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \ | ||
733 | DBGMODE) | ||
734 | |||
735 | #define LmCONTROL(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \ | ||
736 | ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \ | ||
737 | CONTROL) | ||
738 | |||
739 | #define LmARP2BREAKADR01(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \ | ||
740 | ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \ | ||
741 | ARP2BREAKADR01) | ||
742 | |||
743 | #define LmARP2BREAKADR23(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \ | ||
744 | ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \ | ||
745 | ARP2BREAKADR23) | ||
746 | |||
747 | #define LmMODECTL(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \ | ||
748 | ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \ | ||
749 | MODECTL) | ||
750 | |||
751 | #define LmAUTODISCI 0x08000000 | ||
752 | #define LmDSBLBITLT 0x04000000 | ||
753 | #define LmDSBLANTT 0x02000000 | ||
754 | #define LmDSBLCRTT 0x01000000 | ||
755 | #define LmDSBLCONT 0x00000100 | ||
756 | #define LmPRIMODE 0x00000080 | ||
757 | #define LmDSBLHOLD 0x00000040 | ||
758 | #define LmDISACK 0x00000020 | ||
759 | #define LmBLIND48 0x00000010 | ||
760 | #define LmRCVMODE_MASK 0x0000000C | ||
761 | #define LmRCVMODE_PLD 0x00000000 | ||
762 | #define LmRCVMODE_HPC 0x00000004 | ||
763 | |||
764 | #define LmDBGMODE(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \ | ||
765 | ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \ | ||
766 | DBGMODE) | ||
767 | |||
768 | #define LmFRCPERR 0x80000000 | ||
769 | #define LmMEMSEL_MASK 0x30000000 | ||
770 | #define LmFRCRBPERR 0x00000000 | ||
771 | #define LmFRCTBPERR 0x10000000 | ||
772 | #define LmFRCSGBPERR 0x20000000 | ||
773 | #define LmFRCARBPERR 0x30000000 | ||
774 | #define LmRCVIDW 0x00080000 | ||
775 | #define LmINVDWERR 0x00040000 | ||
776 | #define LmRCVDISP 0x00004000 | ||
777 | #define LmDISPERR 0x00002000 | ||
778 | #define LmDSBLDSCR 0x00000800 | ||
779 | #define LmDSBLSCR 0x00000400 | ||
780 | #define LmFRCNAK 0x00000200 | ||
781 | #define LmFRCROFS 0x00000100 | ||
782 | #define LmFRCCRC 0x00000080 | ||
783 | #define LmFRMTYPE_MASK 0x00000070 | ||
784 | #define LmSG_DATA 0x00000000 | ||
785 | #define LmSG_COMMAND 0x00000010 | ||
786 | #define LmSG_TASK 0x00000020 | ||
787 | #define LmSG_TGTXFER 0x00000030 | ||
788 | #define LmSG_RESPONSE 0x00000040 | ||
789 | #define LmSG_IDENADDR 0x00000050 | ||
790 | #define LmSG_OPENADDR 0x00000060 | ||
791 | #define LmDISCRCGEN 0x00000008 | ||
792 | #define LmDISCRCCHK 0x00000004 | ||
793 | #define LmSSXMTFRM 0x00000002 | ||
794 | #define LmSSRCVFRM 0x00000001 | ||
795 | |||
796 | #define LmCONTROL(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \ | ||
797 | ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \ | ||
798 | CONTROL) | ||
799 | |||
800 | #define LmSTEPXMTFRM 0x00000002 | ||
801 | #define LmSTEPRCVFRM 0x00000001 | ||
802 | |||
803 | #define LmBISTCTL0(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \ | ||
804 | ((LinkNum)*LmSEQ_HOST_REG_SIZE) + \ | ||
805 | BISTCTL0) | ||
806 | |||
807 | #define ARBBISTEN 0x40000000 | ||
808 | #define ARBBISTDN 0x20000000 /* ro */ | ||
809 | #define ARBBISTFAIL 0x10000000 /* ro */ | ||
810 | #define TBBISTEN 0x00000400 | ||
811 | #define TBBISTDN 0x00000200 /* ro */ | ||
812 | #define TBBISTFAIL 0x00000100 /* ro */ | ||
813 | #define RBBISTEN 0x00000040 | ||
814 | #define RBBISTDN 0x00000020 /* ro */ | ||
815 | #define RBBISTFAIL 0x00000010 /* ro */ | ||
816 | #define SGBISTEN 0x00000004 | ||
817 | #define SGBISTDN 0x00000002 /* ro */ | ||
818 | #define SGBISTFAIL 0x00000001 /* ro */ | ||
819 | |||
820 | #define LmBISTCTL1(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \ | ||
821 | ((LinkNum)*LmSEQ_HOST_REG_SIZE) +\ | ||
822 | BISTCTL1) | ||
823 | |||
824 | #define LmRAMPAGE1 0x00000200 | ||
825 | #define LmRAMPAGE0 0x00000100 | ||
826 | #define LmIMEMBISTEN 0x00000040 | ||
827 | #define LmIMEMBISTDN 0x00000020 /* ro */ | ||
828 | #define LmIMEMBISTFAIL 0x00000010 /* ro */ | ||
829 | #define LmSCRBISTEN 0x00000004 | ||
830 | #define LmSCRBISTDN 0x00000002 /* ro */ | ||
831 | #define LmSCRBISTFAIL 0x00000001 /* ro */ | ||
832 | #define LmRAMPAGE (LmRAMPAGE1 + LmRAMPAGE0) | ||
833 | #define LmRAMPAGE_LSHIFT 0x8 | ||
834 | |||
835 | #define LmSCRATCH(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \ | ||
836 | ((LinkNum) * LmSEQ_HOST_REG_SIZE) +\ | ||
837 | MAPPEDSCR) | ||
838 | |||
839 | #define LmSEQRAM(LinkNum) (LSEQ0_HOST_REG_BASE_ADR + \ | ||
840 | ((LinkNum) * LmSEQ_HOST_REG_SIZE) +\ | ||
841 | LSEQRAM) | ||
842 | |||
843 | /* | ||
844 | * LmSEQ CIO Bus Register, Address Range : (0x0000-0xFFC) | ||
845 | * 8 modes, each mode is 512 bytes. | ||
846 | * Unless specified, the register should valid for all modes. | ||
847 | */ | ||
848 | #define LmSEQ_CIOBUS_REG_BASE 0x2000 | ||
849 | |||
850 | #define LmSEQ_PHY_BASE(Mode, LinkNum) \ | ||
851 | (LSEQ0_HOST_REG_BASE_ADR + \ | ||
852 | (LmSEQ_HOST_REG_SIZE * (u32) (LinkNum)) + \ | ||
853 | LmSEQ_CIOBUS_REG_BASE + \ | ||
854 | ((u32) (Mode) * LmSEQ_MODE_PAGE_SIZE)) | ||
855 | |||
856 | #define LmSEQ_PHY_REG(Mode, LinkNum, Reg) \ | ||
857 | (LmSEQ_PHY_BASE(Mode, LinkNum) + (u32) (Reg)) | ||
858 | |||
859 | #define LmMODEPTR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, MODEPTR) | ||
860 | |||
861 | #define LmALTMODE(LinkNum) LmSEQ_PHY_REG(0, LinkNum, ALTMODE) | ||
862 | |||
863 | #define LmATOMICXCHG(LinkNum) LmSEQ_PHY_REG(0, LinkNum, ATOMICXCHG) | ||
864 | |||
865 | #define LmFLAG(LinkNum) LmSEQ_PHY_REG(0, LinkNum, FLAG) | ||
866 | |||
867 | #define LmARP2INTCTL(LinkNum) LmSEQ_PHY_REG(0, LinkNum, ARP2INTCTL) | ||
868 | |||
869 | #define LmSTACK(LinkNum) LmSEQ_PHY_REG(0, LinkNum, STACK) | ||
870 | |||
871 | #define LmFUNCTION1(LinkNum) LmSEQ_PHY_REG(0, LinkNum, FUNCTION1) | ||
872 | |||
873 | #define LmPRGMCNT(LinkNum) LmSEQ_PHY_REG(0, LinkNum, PRGMCNT) | ||
874 | |||
875 | #define LmACCUM(LinkNum) LmSEQ_PHY_REG(0, LinkNum, ACCUM) | ||
876 | |||
877 | #define LmSINDEX(LinkNum) LmSEQ_PHY_REG(0, LinkNum, SINDEX) | ||
878 | |||
879 | #define LmDINDEX(LinkNum) LmSEQ_PHY_REG(0, LinkNum, DINDEX) | ||
880 | |||
881 | #define LmALLONES(LinkNum) LmSEQ_PHY_REG(0, LinkNum, ALLONES) | ||
882 | |||
883 | #define LmALLZEROS(LinkNum) LmSEQ_PHY_REG(0, LinkNum, ALLZEROS) | ||
884 | |||
885 | #define LmSINDIR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, SINDIR) | ||
886 | |||
887 | #define LmDINDIR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, DINDIR) | ||
888 | |||
889 | #define LmJUMLDIR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, JUMLDIR) | ||
890 | |||
891 | #define LmARP2HALTCODE(LinkNum) LmSEQ_PHY_REG(0, LinkNum, ARP2HALTCODE) | ||
892 | |||
893 | #define LmCURRADDR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, CURRADDR) | ||
894 | |||
895 | #define LmLASTADDR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, LASTADDR) | ||
896 | |||
897 | #define LmNXTLADDR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, NXTLADDR) | ||
898 | |||
899 | #define LmDBGPORTPTR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, DBGPORTPTR) | ||
900 | |||
901 | #define LmDBGPORT(LinkNum) LmSEQ_PHY_REG(0, LinkNum, DBGPORT) | ||
902 | |||
903 | #define LmSCRATCHPAGE(LinkNum) LmSEQ_PHY_REG(0, LinkNum, SCRATCHPAGE) | ||
904 | |||
905 | #define LmMnSCRATCHPAGE(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, \ | ||
906 | MnSCRATCHPAGE) | ||
907 | |||
908 | #define LmTIMERCALC(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x28) | ||
909 | |||
910 | #define LmREQMBX(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x30) | ||
911 | |||
912 | #define LmRSPMBX(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x34) | ||
913 | |||
914 | #define LmMnINT(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x38) | ||
915 | |||
916 | #define CTXMEMSIZE 0x80000000 /* ro */ | ||
917 | #define LmACKREQ 0x08000000 | ||
918 | #define LmNAKREQ 0x04000000 | ||
919 | #define LmMnXMTERR 0x02000000 | ||
920 | #define LmM5OOBSVC 0x01000000 | ||
921 | #define LmHWTINT 0x00800000 | ||
922 | #define LmMnCTXDONE 0x00100000 | ||
923 | #define LmM2REQMBXF 0x00080000 | ||
924 | #define LmM2RSPMBXE 0x00040000 | ||
925 | #define LmMnDMAERR 0x00020000 | ||
926 | #define LmRCVPRIM 0x00010000 | ||
927 | #define LmRCVERR 0x00008000 | ||
928 | #define LmADDRRCV 0x00004000 | ||
929 | #define LmMnHDRMISS 0x00002000 | ||
930 | #define LmMnWAITSCB 0x00001000 | ||
931 | #define LmMnRLSSCB 0x00000800 | ||
932 | #define LmMnSAVECTX 0x00000400 | ||
933 | #define LmMnFETCHSG 0x00000200 | ||
934 | #define LmMnLOADCTX 0x00000100 | ||
935 | #define LmMnCFGICL 0x00000080 | ||
936 | #define LmMnCFGSATA 0x00000040 | ||
937 | #define LmMnCFGEXPSATA 0x00000020 | ||
938 | #define LmMnCFGCMPLT 0x00000010 | ||
939 | #define LmMnCFGRBUF 0x00000008 | ||
940 | #define LmMnSAVETTR 0x00000004 | ||
941 | #define LmMnCFGRDAT 0x00000002 | ||
942 | #define LmMnCFGHDR 0x00000001 | ||
943 | |||
944 | #define LmMnINTEN(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x3C) | ||
945 | |||
946 | #define EN_LmACKREQ 0x08000000 | ||
947 | #define EN_LmNAKREQ 0x04000000 | ||
948 | #define EN_LmMnXMTERR 0x02000000 | ||
949 | #define EN_LmM5OOBSVC 0x01000000 | ||
950 | #define EN_LmHWTINT 0x00800000 | ||
951 | #define EN_LmMnCTXDONE 0x00100000 | ||
952 | #define EN_LmM2REQMBXF 0x00080000 | ||
953 | #define EN_LmM2RSPMBXE 0x00040000 | ||
954 | #define EN_LmMnDMAERR 0x00020000 | ||
955 | #define EN_LmRCVPRIM 0x00010000 | ||
956 | #define EN_LmRCVERR 0x00008000 | ||
957 | #define EN_LmADDRRCV 0x00004000 | ||
958 | #define EN_LmMnHDRMISS 0x00002000 | ||
959 | #define EN_LmMnWAITSCB 0x00001000 | ||
960 | #define EN_LmMnRLSSCB 0x00000800 | ||
961 | #define EN_LmMnSAVECTX 0x00000400 | ||
962 | #define EN_LmMnFETCHSG 0x00000200 | ||
963 | #define EN_LmMnLOADCTX 0x00000100 | ||
964 | #define EN_LmMnCFGICL 0x00000080 | ||
965 | #define EN_LmMnCFGSATA 0x00000040 | ||
966 | #define EN_LmMnCFGEXPSATA 0x00000020 | ||
967 | #define EN_LmMnCFGCMPLT 0x00000010 | ||
968 | #define EN_LmMnCFGRBUF 0x00000008 | ||
969 | #define EN_LmMnSAVETTR 0x00000004 | ||
970 | #define EN_LmMnCFGRDAT 0x00000002 | ||
971 | #define EN_LmMnCFGHDR 0x00000001 | ||
972 | |||
973 | #define LmM0INTEN_MASK (EN_LmMnCFGCMPLT | EN_LmMnCFGRBUF | \ | ||
974 | EN_LmMnSAVETTR | EN_LmMnCFGRDAT | \ | ||
975 | EN_LmMnCFGHDR | EN_LmRCVERR | \ | ||
976 | EN_LmADDRRCV | EN_LmMnHDRMISS | \ | ||
977 | EN_LmMnRLSSCB | EN_LmMnSAVECTX | \ | ||
978 | EN_LmMnFETCHSG | EN_LmMnLOADCTX | \ | ||
979 | EN_LmHWTINT | EN_LmMnCTXDONE | \ | ||
980 | EN_LmRCVPRIM | EN_LmMnCFGSATA | \ | ||
981 | EN_LmMnCFGEXPSATA | EN_LmMnDMAERR) | ||
982 | |||
983 | #define LmM1INTEN_MASK (EN_LmMnCFGCMPLT | EN_LmADDRRCV | \ | ||
984 | EN_LmMnRLSSCB | EN_LmMnSAVECTX | \ | ||
985 | EN_LmMnFETCHSG | EN_LmMnLOADCTX | \ | ||
986 | EN_LmMnXMTERR | EN_LmHWTINT | \ | ||
987 | EN_LmMnCTXDONE | EN_LmRCVPRIM | \ | ||
988 | EN_LmRCVERR | EN_LmMnDMAERR) | ||
989 | |||
990 | #define LmM2INTEN_MASK (EN_LmADDRRCV | EN_LmHWTINT | \ | ||
991 | EN_LmM2REQMBXF | EN_LmRCVPRIM | \ | ||
992 | EN_LmRCVERR) | ||
993 | |||
994 | #define LmM5INTEN_MASK (EN_LmADDRRCV | EN_LmM5OOBSVC | \ | ||
995 | EN_LmHWTINT | EN_LmRCVPRIM | \ | ||
996 | EN_LmRCVERR) | ||
997 | |||
998 | #define LmXMTPRIMD(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x40) | ||
999 | |||
1000 | #define LmXMTPRIMCS(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x44) | ||
1001 | |||
1002 | #define LmCONSTAT(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x45) | ||
1003 | |||
1004 | #define LmMnDMAERRS(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x46) | ||
1005 | |||
1006 | #define LmMnSGDMAERRS(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x47) | ||
1007 | |||
1008 | #define LmM0EXPHDRP(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x48) | ||
1009 | |||
1010 | #define LmM1SASALIGN(LinkNum) LmSEQ_PHY_REG(1, LinkNum, 0x48) | ||
1011 | #define SAS_ALIGN_DEFAULT 0xFF | ||
1012 | |||
1013 | #define LmM0MSKHDRP(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x49) | ||
1014 | |||
1015 | #define LmM1STPALIGN(LinkNum) LmSEQ_PHY_REG(1, LinkNum, 0x49) | ||
1016 | #define STP_ALIGN_DEFAULT 0x1F | ||
1017 | |||
1018 | #define LmM0RCVHDRP(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x4A) | ||
1019 | |||
1020 | #define LmM1XMTHDRP(LinkNum) LmSEQ_PHY_REG(1, LinkNum, 0x4A) | ||
1021 | |||
1022 | #define LmM0ICLADR(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x4B) | ||
1023 | |||
1024 | #define LmM1ALIGNMODE(LinkNum) LmSEQ_PHY_REG(1, LinkNum, 0x4B) | ||
1025 | |||
1026 | #define LmDISALIGN 0x20 | ||
1027 | #define LmROTSTPALIGN 0x10 | ||
1028 | #define LmSTPALIGN 0x08 | ||
1029 | #define LmROTNOTIFY 0x04 | ||
1030 | #define LmDUALALIGN 0x02 | ||
1031 | #define LmROTALIGN 0x01 | ||
1032 | |||
1033 | #define LmM0EXPRCVNT(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x4C) | ||
1034 | |||
1035 | #define LmM1XMTCNT(LinkNum) LmSEQ_PHY_REG(1, LinkNum, 0x4C) | ||
1036 | |||
1037 | #define LmMnBUFSTAT(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x4E) | ||
1038 | |||
1039 | #define LmMnBUFPERR 0x01 | ||
1040 | |||
1041 | /* mode 0-1 */ | ||
1042 | #define LmMnXFRLVL(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x59) | ||
1043 | |||
1044 | #define LmMnXFRLVL_128 0x05 | ||
1045 | #define LmMnXFRLVL_256 0x04 | ||
1046 | #define LmMnXFRLVL_512 0x03 | ||
1047 | #define LmMnXFRLVL_1024 0x02 | ||
1048 | #define LmMnXFRLVL_1536 0x01 | ||
1049 | #define LmMnXFRLVL_2048 0x00 | ||
1050 | |||
1051 | /* mode 0-1 */ | ||
1052 | #define LmMnSGDMACTL(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x5A) | ||
1053 | |||
1054 | #define LmMnRESETSG 0x04 | ||
1055 | #define LmMnSTOPSG 0x02 | ||
1056 | #define LmMnSTARTSG 0x01 | ||
1057 | |||
1058 | /* mode 0-1 */ | ||
1059 | #define LmMnSGDMASTAT(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x5B) | ||
1060 | |||
1061 | /* mode 0-1 */ | ||
1062 | #define LmMnDDMACTL(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x5C) | ||
1063 | |||
1064 | #define LmMnFLUSH 0x40 /* wo */ | ||
1065 | #define LmMnRLSRTRY 0x20 /* wo */ | ||
1066 | #define LmMnDISCARD 0x10 /* wo */ | ||
1067 | #define LmMnRESETDAT 0x08 /* wo */ | ||
1068 | #define LmMnSUSDAT 0x04 /* wo */ | ||
1069 | #define LmMnSTOPDAT 0x02 /* wo */ | ||
1070 | #define LmMnSTARTDAT 0x01 /* wo */ | ||
1071 | |||
1072 | /* mode 0-1 */ | ||
1073 | #define LmMnDDMASTAT(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x5D) | ||
1074 | |||
1075 | #define LmMnDPEMPTY 0x80 | ||
1076 | #define LmMnFLUSHING 0x40 | ||
1077 | #define LmMnDDMAREQ 0x20 | ||
1078 | #define LmMnHDMAREQ 0x10 | ||
1079 | #define LmMnDATFREE 0x08 | ||
1080 | #define LmMnDATSUS 0x04 | ||
1081 | #define LmMnDATACT 0x02 | ||
1082 | #define LmMnDATEN 0x01 | ||
1083 | |||
1084 | /* mode 0-1 */ | ||
1085 | #define LmMnDDMAMODE(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x5E) | ||
1086 | |||
1087 | #define LmMnDMATYPE_NORMAL 0x0000 | ||
1088 | #define LmMnDMATYPE_HOST_ONLY_TX 0x0001 | ||
1089 | #define LmMnDMATYPE_DEVICE_ONLY_TX 0x0002 | ||
1090 | #define LmMnDMATYPE_INVALID 0x0003 | ||
1091 | #define LmMnDMATYPE_MASK 0x0003 | ||
1092 | |||
1093 | #define LmMnDMAWRAP 0x0004 | ||
1094 | #define LmMnBITBUCKET 0x0008 | ||
1095 | #define LmMnDISHDR 0x0010 | ||
1096 | #define LmMnSTPCRC 0x0020 | ||
1097 | #define LmXTEST 0x0040 | ||
1098 | #define LmMnDISCRC 0x0080 | ||
1099 | #define LmMnENINTLK 0x0100 | ||
1100 | #define LmMnADDRFRM 0x0400 | ||
1101 | #define LmMnENXMTCRC 0x0800 | ||
1102 | |||
1103 | /* mode 0-1 */ | ||
1104 | #define LmMnXFRCNT(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x70) | ||
1105 | |||
1106 | /* mode 0-1 */ | ||
1107 | #define LmMnDPSEL(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x7B) | ||
1108 | #define LmMnDPSEL_MASK 0x07 | ||
1109 | #define LmMnEOLPRE 0x40 | ||
1110 | #define LmMnEOSPRE 0x80 | ||
1111 | |||
1112 | /* Registers used in conjunction with LmMnDPSEL and LmMnDPACC registers */ | ||
1113 | /* Receive Mode n = 0 */ | ||
1114 | #define LmMnHRADDR 0x00 | ||
1115 | #define LmMnHBYTECNT 0x01 | ||
1116 | #define LmMnHREWIND 0x02 | ||
1117 | #define LmMnDWADDR 0x03 | ||
1118 | #define LmMnDSPACECNT 0x04 | ||
1119 | #define LmMnDFRMSIZE 0x05 | ||
1120 | |||
1121 | /* Registers used in conjunction with LmMnDPSEL and LmMnDPACC registers */ | ||
1122 | /* Transmit Mode n = 1 */ | ||
1123 | #define LmMnHWADDR 0x00 | ||
1124 | #define LmMnHSPACECNT 0x01 | ||
1125 | /* #define LmMnHREWIND 0x02 */ | ||
1126 | #define LmMnDRADDR 0x03 | ||
1127 | #define LmMnDBYTECNT 0x04 | ||
1128 | /* #define LmMnDFRMSIZE 0x05 */ | ||
1129 | |||
1130 | /* mode 0-1 */ | ||
1131 | #define LmMnDPACC(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x78) | ||
1132 | #define LmMnDPACC_MASK 0x00FFFFFF | ||
1133 | |||
1134 | /* mode 0-1 */ | ||
1135 | #define LmMnHOLDLVL(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x7D) | ||
1136 | |||
1137 | #define LmPRMSTAT0(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x80) | ||
1138 | #define LmPRMSTAT0BYTE0 0x80 | ||
1139 | #define LmPRMSTAT0BYTE1 0x81 | ||
1140 | #define LmPRMSTAT0BYTE2 0x82 | ||
1141 | #define LmPRMSTAT0BYTE3 0x83 | ||
1142 | |||
1143 | #define LmFRAMERCVD 0x80000000 | ||
1144 | #define LmXFRRDYRCVD 0x40000000 | ||
1145 | #define LmUNKNOWNP 0x20000000 | ||
1146 | #define LmBREAK 0x10000000 | ||
1147 | #define LmDONE 0x08000000 | ||
1148 | #define LmOPENACPT 0x04000000 | ||
1149 | #define LmOPENRJCT 0x02000000 | ||
1150 | #define LmOPENRTRY 0x01000000 | ||
1151 | #define LmCLOSERV1 0x00800000 | ||
1152 | #define LmCLOSERV0 0x00400000 | ||
1153 | #define LmCLOSENORM 0x00200000 | ||
1154 | #define LmCLOSECLAF 0x00100000 | ||
1155 | #define LmNOTIFYRV2 0x00080000 | ||
1156 | #define LmNOTIFYRV1 0x00040000 | ||
1157 | #define LmNOTIFYRV0 0x00020000 | ||
1158 | #define LmNOTIFYSPIN 0x00010000 | ||
1159 | #define LmBROADRV4 0x00008000 | ||
1160 | #define LmBROADRV3 0x00004000 | ||
1161 | #define LmBROADRV2 0x00002000 | ||
1162 | #define LmBROADRV1 0x00001000 | ||
1163 | #define LmBROADSES 0x00000800 | ||
1164 | #define LmBROADRVCH1 0x00000400 | ||
1165 | #define LmBROADRVCH0 0x00000200 | ||
1166 | #define LmBROADCH 0x00000100 | ||
1167 | #define LmAIPRVWP 0x00000080 | ||
1168 | #define LmAIPWP 0x00000040 | ||
1169 | #define LmAIPWD 0x00000020 | ||
1170 | #define LmAIPWC 0x00000010 | ||
1171 | #define LmAIPRV2 0x00000008 | ||
1172 | #define LmAIPRV1 0x00000004 | ||
1173 | #define LmAIPRV0 0x00000002 | ||
1174 | #define LmAIPNRML 0x00000001 | ||
1175 | |||
1176 | #define LmBROADCAST_MASK (LmBROADCH | LmBROADRVCH0 | \ | ||
1177 | LmBROADRVCH1) | ||
1178 | |||
1179 | #define LmPRMSTAT1(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0x84) | ||
1180 | #define LmPRMSTAT1BYTE0 0x84 | ||
1181 | #define LmPRMSTAT1BYTE1 0x85 | ||
1182 | #define LmPRMSTAT1BYTE2 0x86 | ||
1183 | #define LmPRMSTAT1BYTE3 0x87 | ||
1184 | |||
1185 | #define LmFRMRCVDSTAT 0x80000000 | ||
1186 | #define LmBREAK_DET 0x04000000 | ||
1187 | #define LmCLOSE_DET 0x02000000 | ||
1188 | #define LmDONE_DET 0x01000000 | ||
1189 | #define LmXRDY 0x00040000 | ||
1190 | #define LmSYNCSRST 0x00020000 | ||
1191 | #define LmSYNC 0x00010000 | ||
1192 | #define LmXHOLD 0x00008000 | ||
1193 | #define LmRRDY 0x00004000 | ||
1194 | #define LmHOLD 0x00002000 | ||
1195 | #define LmROK 0x00001000 | ||
1196 | #define LmRIP 0x00000800 | ||
1197 | #define LmCRBLK 0x00000400 | ||
1198 | #define LmACK 0x00000200 | ||
1199 | #define LmNAK 0x00000100 | ||
1200 | #define LmHARDRST 0x00000080 | ||
1201 | #define LmERROR 0x00000040 | ||
1202 | #define LmRERR 0x00000020 | ||
1203 | #define LmPMREQP 0x00000010 | ||
1204 | #define LmPMREQS 0x00000008 | ||
1205 | #define LmPMACK 0x00000004 | ||
1206 | #define LmPMNAK 0x00000002 | ||
1207 | #define LmDMAT 0x00000001 | ||
1208 | |||
1209 | /* mode 1 */ | ||
1210 | #define LmMnSATAFS(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x7E) | ||
1211 | #define LmMnXMTSIZE(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0x93) | ||
1212 | |||
1213 | /* mode 0 */ | ||
1214 | #define LmMnFRMERR(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0xB0) | ||
1215 | |||
1216 | #define LmACRCERR 0x00000800 | ||
1217 | #define LmPHYOVRN 0x00000400 | ||
1218 | #define LmOBOVRN 0x00000200 | ||
1219 | #define LmMnZERODATA 0x00000100 | ||
1220 | #define LmSATAINTLK 0x00000080 | ||
1221 | #define LmMnCRCERR 0x00000020 | ||
1222 | #define LmRRDYOVRN 0x00000010 | ||
1223 | #define LmMISSSOAF 0x00000008 | ||
1224 | #define LmMISSSOF 0x00000004 | ||
1225 | #define LmMISSEOAF 0x00000002 | ||
1226 | #define LmMISSEOF 0x00000001 | ||
1227 | |||
1228 | #define LmFRMERREN(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xB4) | ||
1229 | |||
1230 | #define EN_LmACRCERR 0x00000800 | ||
1231 | #define EN_LmPHYOVRN 0x00000400 | ||
1232 | #define EN_LmOBOVRN 0x00000200 | ||
1233 | #define EN_LmMnZERODATA 0x00000100 | ||
1234 | #define EN_LmSATAINTLK 0x00000080 | ||
1235 | #define EN_LmFRMBAD 0x00000040 | ||
1236 | #define EN_LmMnCRCERR 0x00000020 | ||
1237 | #define EN_LmRRDYOVRN 0x00000010 | ||
1238 | #define EN_LmMISSSOAF 0x00000008 | ||
1239 | #define EN_LmMISSSOF 0x00000004 | ||
1240 | #define EN_LmMISSEOAF 0x00000002 | ||
1241 | #define EN_LmMISSEOF 0x00000001 | ||
1242 | |||
1243 | #define LmFRMERREN_MASK (EN_LmSATAINTLK | EN_LmMnCRCERR | \ | ||
1244 | EN_LmRRDYOVRN | EN_LmMISSSOF | \ | ||
1245 | EN_LmMISSEOAF | EN_LmMISSEOF | \ | ||
1246 | EN_LmACRCERR | LmPHYOVRN | \ | ||
1247 | EN_LmOBOVRN | EN_LmMnZERODATA) | ||
1248 | |||
1249 | #define LmHWTSTATEN(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xC5) | ||
1250 | |||
1251 | #define EN_LmDONETO 0x80 | ||
1252 | #define EN_LmINVDISP 0x40 | ||
1253 | #define EN_LmINVDW 0x20 | ||
1254 | #define EN_LmDWSEVENT 0x08 | ||
1255 | #define EN_LmCRTTTO 0x04 | ||
1256 | #define EN_LmANTTTO 0x02 | ||
1257 | #define EN_LmBITLTTO 0x01 | ||
1258 | |||
1259 | #define LmHWTSTATEN_MASK (EN_LmINVDISP | EN_LmINVDW | \ | ||
1260 | EN_LmDWSEVENT | EN_LmCRTTTO | \ | ||
1261 | EN_LmANTTTO | EN_LmDONETO | \ | ||
1262 | EN_LmBITLTTO) | ||
1263 | |||
1264 | #define LmHWTSTAT(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xC7) | ||
1265 | |||
1266 | #define LmDONETO 0x80 | ||
1267 | #define LmINVDISP 0x40 | ||
1268 | #define LmINVDW 0x20 | ||
1269 | #define LmDWSEVENT 0x08 | ||
1270 | #define LmCRTTTO 0x04 | ||
1271 | #define LmANTTTO 0x02 | ||
1272 | #define LmBITLTTO 0x01 | ||
1273 | |||
1274 | #define LmMnDATABUFADR(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0xC8) | ||
1275 | #define LmDATABUFADR_MASK 0x0FFF | ||
1276 | |||
1277 | #define LmMnDATABUF(LinkNum, Mode) LmSEQ_PHY_REG(Mode, LinkNum, 0xCA) | ||
1278 | |||
1279 | #define LmPRIMSTAT0EN(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xE0) | ||
1280 | |||
1281 | #define EN_LmUNKNOWNP 0x20000000 | ||
1282 | #define EN_LmBREAK 0x10000000 | ||
1283 | #define EN_LmDONE 0x08000000 | ||
1284 | #define EN_LmOPENACPT 0x04000000 | ||
1285 | #define EN_LmOPENRJCT 0x02000000 | ||
1286 | #define EN_LmOPENRTRY 0x01000000 | ||
1287 | #define EN_LmCLOSERV1 0x00800000 | ||
1288 | #define EN_LmCLOSERV0 0x00400000 | ||
1289 | #define EN_LmCLOSENORM 0x00200000 | ||
1290 | #define EN_LmCLOSECLAF 0x00100000 | ||
1291 | #define EN_LmNOTIFYRV2 0x00080000 | ||
1292 | #define EN_LmNOTIFYRV1 0x00040000 | ||
1293 | #define EN_LmNOTIFYRV0 0x00020000 | ||
1294 | #define EN_LmNOTIFYSPIN 0x00010000 | ||
1295 | #define EN_LmBROADRV4 0x00008000 | ||
1296 | #define EN_LmBROADRV3 0x00004000 | ||
1297 | #define EN_LmBROADRV2 0x00002000 | ||
1298 | #define EN_LmBROADRV1 0x00001000 | ||
1299 | #define EN_LmBROADRV0 0x00000800 | ||
1300 | #define EN_LmBROADRVCH1 0x00000400 | ||
1301 | #define EN_LmBROADRVCH0 0x00000200 | ||
1302 | #define EN_LmBROADCH 0x00000100 | ||
1303 | #define EN_LmAIPRVWP 0x00000080 | ||
1304 | #define EN_LmAIPWP 0x00000040 | ||
1305 | #define EN_LmAIPWD 0x00000020 | ||
1306 | #define EN_LmAIPWC 0x00000010 | ||
1307 | #define EN_LmAIPRV2 0x00000008 | ||
1308 | #define EN_LmAIPRV1 0x00000004 | ||
1309 | #define EN_LmAIPRV0 0x00000002 | ||
1310 | #define EN_LmAIPNRML 0x00000001 | ||
1311 | |||
1312 | #define LmPRIMSTAT0EN_MASK (EN_LmBREAK | \ | ||
1313 | EN_LmDONE | EN_LmOPENACPT | \ | ||
1314 | EN_LmOPENRJCT | EN_LmOPENRTRY | \ | ||
1315 | EN_LmCLOSERV1 | EN_LmCLOSERV0 | \ | ||
1316 | EN_LmCLOSENORM | EN_LmCLOSECLAF | \ | ||
1317 | EN_LmBROADRV4 | EN_LmBROADRV3 | \ | ||
1318 | EN_LmBROADRV2 | EN_LmBROADRV1 | \ | ||
1319 | EN_LmBROADRV0 | EN_LmBROADRVCH1 | \ | ||
1320 | EN_LmBROADRVCH0 | EN_LmBROADCH | \ | ||
1321 | EN_LmAIPRVWP | EN_LmAIPWP | \ | ||
1322 | EN_LmAIPWD | EN_LmAIPWC | \ | ||
1323 | EN_LmAIPRV2 | EN_LmAIPRV1 | \ | ||
1324 | EN_LmAIPRV0 | EN_LmAIPNRML) | ||
1325 | |||
1326 | #define LmPRIMSTAT1EN(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xE4) | ||
1327 | |||
1328 | #define EN_LmXRDY 0x00040000 | ||
1329 | #define EN_LmSYNCSRST 0x00020000 | ||
1330 | #define EN_LmSYNC 0x00010000 | ||
1331 | #define EN_LmXHOLD 0x00008000 | ||
1332 | #define EN_LmRRDY 0x00004000 | ||
1333 | #define EN_LmHOLD 0x00002000 | ||
1334 | #define EN_LmROK 0x00001000 | ||
1335 | #define EN_LmRIP 0x00000800 | ||
1336 | #define EN_LmCRBLK 0x00000400 | ||
1337 | #define EN_LmACK 0x00000200 | ||
1338 | #define EN_LmNAK 0x00000100 | ||
1339 | #define EN_LmHARDRST 0x00000080 | ||
1340 | #define EN_LmERROR 0x00000040 | ||
1341 | #define EN_LmRERR 0x00000020 | ||
1342 | #define EN_LmPMREQP 0x00000010 | ||
1343 | #define EN_LmPMREQS 0x00000008 | ||
1344 | #define EN_LmPMACK 0x00000004 | ||
1345 | #define EN_LmPMNAK 0x00000002 | ||
1346 | #define EN_LmDMAT 0x00000001 | ||
1347 | |||
1348 | #define LmPRIMSTAT1EN_MASK (EN_LmHARDRST | \ | ||
1349 | EN_LmSYNCSRST | \ | ||
1350 | EN_LmPMREQP | EN_LmPMREQS | \ | ||
1351 | EN_LmPMACK | EN_LmPMNAK) | ||
1352 | |||
1353 | #define LmSMSTATE(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xE8) | ||
1354 | |||
1355 | #define LmSMSTATEBRK(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xEC) | ||
1356 | |||
1357 | #define LmSMDBGCTL(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xF0) | ||
1358 | |||
1359 | |||
1360 | /* | ||
1361 | * LmSEQ CIO Bus Mode 3 Register. | ||
1362 | * Mode 3: Configuration and Setup, IOP Context SCB. | ||
1363 | */ | ||
1364 | #define LmM3SATATIMER(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x48) | ||
1365 | |||
1366 | #define LmM3INTVEC0(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x90) | ||
1367 | |||
1368 | #define LmM3INTVEC1(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x92) | ||
1369 | |||
1370 | #define LmM3INTVEC2(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x94) | ||
1371 | |||
1372 | #define LmM3INTVEC3(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x96) | ||
1373 | |||
1374 | #define LmM3INTVEC4(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x98) | ||
1375 | |||
1376 | #define LmM3INTVEC5(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x9A) | ||
1377 | |||
1378 | #define LmM3INTVEC6(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x9C) | ||
1379 | |||
1380 | #define LmM3INTVEC7(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0x9E) | ||
1381 | |||
1382 | #define LmM3INTVEC8(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0xA4) | ||
1383 | |||
1384 | #define LmM3INTVEC9(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0xA6) | ||
1385 | |||
1386 | #define LmM3INTVEC10(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0xB0) | ||
1387 | |||
1388 | #define LmM3FRMGAP(LinkNum) LmSEQ_PHY_REG(3, LinkNum, 0xB4) | ||
1389 | |||
1390 | #define LmBITL_TIMER(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xA2) | ||
1391 | |||
1392 | #define LmWWN(LinkNum) LmSEQ_PHY_REG(0, LinkNum, 0xA8) | ||
1393 | |||
1394 | |||
1395 | /* | ||
1396 | * LmSEQ CIO Bus Mode 5 Registers. | ||
1397 | * Mode 5: Phy/OOB Control and Status. | ||
1398 | */ | ||
1399 | #define LmSEQ_OOB_REG(phy_id, reg) LmSEQ_PHY_REG(5, (phy_id), (reg)) | ||
1400 | |||
1401 | #define OOB_BFLTR 0x100 | ||
1402 | |||
1403 | #define BFLTR_THR_MASK 0xF0 | ||
1404 | #define BFLTR_TC_MASK 0x0F | ||
1405 | |||
1406 | #define OOB_INIT_MIN 0x102 | ||
1407 | |||
1408 | #define OOB_INIT_MAX 0x104 | ||
1409 | |||
1410 | #define OOB_INIT_NEG 0x106 | ||
1411 | |||
1412 | #define OOB_SAS_MIN 0x108 | ||
1413 | |||
1414 | #define OOB_SAS_MAX 0x10A | ||
1415 | |||
1416 | #define OOB_SAS_NEG 0x10C | ||
1417 | |||
1418 | #define OOB_WAKE_MIN 0x10E | ||
1419 | |||
1420 | #define OOB_WAKE_MAX 0x110 | ||
1421 | |||
1422 | #define OOB_WAKE_NEG 0x112 | ||
1423 | |||
1424 | #define OOB_IDLE_MAX 0x114 | ||
1425 | |||
1426 | #define OOB_BURST_MAX 0x116 | ||
1427 | |||
1428 | #define OOB_DATA_KBITS 0x126 | ||
1429 | |||
1430 | #define OOB_ALIGN_0_DATA 0x12C | ||
1431 | |||
1432 | #define OOB_ALIGN_1_DATA 0x130 | ||
1433 | |||
1434 | #define D10_2_DATA_k 0x00 | ||
1435 | #define SYNC_DATA_k 0x02 | ||
1436 | #define ALIGN_1_DATA_k 0x04 | ||
1437 | #define ALIGN_0_DATA_k 0x08 | ||
1438 | #define BURST_DATA_k 0x10 | ||
1439 | |||
1440 | #define OOB_PHY_RESET_COUNT 0x13C | ||
1441 | |||
1442 | #define OOB_SIG_GEN 0x140 | ||
1443 | |||
1444 | #define START_OOB 0x80 | ||
1445 | #define START_DWS 0x40 | ||
1446 | #define ALIGN_CNT3 0x30 | ||
1447 | #define ALIGN_CNT2 0x20 | ||
1448 | #define ALIGN_CNT1 0x10 | ||
1449 | #define ALIGN_CNT4 0x00 | ||
1450 | #define STOP_DWS 0x08 | ||
1451 | #define SEND_COMSAS 0x04 | ||
1452 | #define SEND_COMINIT 0x02 | ||
1453 | #define SEND_COMWAKE 0x01 | ||
1454 | |||
1455 | #define OOB_XMIT 0x141 | ||
1456 | |||
1457 | #define TX_ENABLE 0x80 | ||
1458 | #define XMIT_OOB_BURST 0x10 | ||
1459 | #define XMIT_D10_2 0x08 | ||
1460 | #define XMIT_SYNC 0x04 | ||
1461 | #define XMIT_ALIGN_1 0x02 | ||
1462 | #define XMIT_ALIGN_0 0x01 | ||
1463 | |||
1464 | #define FUNCTION_MASK 0x142 | ||
1465 | |||
1466 | #define SAS_MODE_DIS 0x80 | ||
1467 | #define SATA_MODE_DIS 0x40 | ||
1468 | #define SPINUP_HOLD_DIS 0x20 | ||
1469 | #define HOT_PLUG_DIS 0x10 | ||
1470 | #define SATA_PS_DIS 0x08 | ||
1471 | #define FUNCTION_MASK_DEFAULT (SPINUP_HOLD_DIS | SATA_PS_DIS) | ||
1472 | |||
1473 | #define OOB_MODE 0x143 | ||
1474 | |||
1475 | #define SAS_MODE 0x80 | ||
1476 | #define SATA_MODE 0x40 | ||
1477 | #define SLOW_CLK 0x20 | ||
1478 | #define FORCE_XMIT_15 0x08 | ||
1479 | #define PHY_SPEED_60 0x04 | ||
1480 | #define PHY_SPEED_30 0x02 | ||
1481 | #define PHY_SPEED_15 0x01 | ||
1482 | |||
1483 | #define CURRENT_STATUS 0x144 | ||
1484 | |||
1485 | #define CURRENT_OOB_DONE 0x80 | ||
1486 | #define CURRENT_LOSS_OF_SIGNAL 0x40 | ||
1487 | #define CURRENT_SPINUP_HOLD 0x20 | ||
1488 | #define CURRENT_HOT_PLUG_CNCT 0x10 | ||
1489 | #define CURRENT_GTO_TIMEOUT 0x08 | ||
1490 | #define CURRENT_OOB_TIMEOUT 0x04 | ||
1491 | #define CURRENT_DEVICE_PRESENT 0x02 | ||
1492 | #define CURRENT_OOB_ERROR 0x01 | ||
1493 | |||
1494 | #define CURRENT_OOB1_ERROR (CURRENT_HOT_PLUG_CNCT | \ | ||
1495 | CURRENT_GTO_TIMEOUT) | ||
1496 | |||
1497 | #define CURRENT_OOB2_ERROR (CURRENT_HOT_PLUG_CNCT | \ | ||
1498 | CURRENT_OOB_ERROR) | ||
1499 | |||
1500 | #define DEVICE_ADDED_W_CNT (CURRENT_OOB_DONE | \ | ||
1501 | CURRENT_HOT_PLUG_CNCT | \ | ||
1502 | CURRENT_DEVICE_PRESENT) | ||
1503 | |||
1504 | #define DEVICE_ADDED_WO_CNT (CURRENT_OOB_DONE | \ | ||
1505 | CURRENT_DEVICE_PRESENT) | ||
1506 | |||
1507 | #define DEVICE_REMOVED CURRENT_LOSS_OF_SIGNAL | ||
1508 | |||
1509 | #define CURRENT_PHY_MASK (CURRENT_OOB_DONE | \ | ||
1510 | CURRENT_LOSS_OF_SIGNAL | \ | ||
1511 | CURRENT_SPINUP_HOLD | \ | ||
1512 | CURRENT_HOT_PLUG_CNCT | \ | ||
1513 | CURRENT_GTO_TIMEOUT | \ | ||
1514 | CURRENT_DEVICE_PRESENT | \ | ||
1515 | CURRENT_OOB_ERROR ) | ||
1516 | |||
1517 | #define CURRENT_ERR_MASK (CURRENT_LOSS_OF_SIGNAL | \ | ||
1518 | CURRENT_GTO_TIMEOUT | \ | ||
1519 | CURRENT_OOB_TIMEOUT | \ | ||
1520 | CURRENT_OOB_ERROR ) | ||
1521 | |||
1522 | #define SPEED_MASK 0x145 | ||
1523 | |||
1524 | #define SATA_SPEED_30_DIS 0x10 | ||
1525 | #define SATA_SPEED_15_DIS 0x08 | ||
1526 | #define SAS_SPEED_60_DIS 0x04 | ||
1527 | #define SAS_SPEED_30_DIS 0x02 | ||
1528 | #define SAS_SPEED_15_DIS 0x01 | ||
1529 | #define SAS_SPEED_MASK_DEFAULT 0x00 | ||
1530 | |||
1531 | #define OOB_TIMER_ENABLE 0x14D | ||
1532 | |||
1533 | #define HOT_PLUG_EN 0x80 | ||
1534 | #define RCD_EN 0x40 | ||
1535 | #define COMTIMER_EN 0x20 | ||
1536 | #define SNTT_EN 0x10 | ||
1537 | #define SNLT_EN 0x04 | ||
1538 | #define SNWT_EN 0x02 | ||
1539 | #define ALIGN_EN 0x01 | ||
1540 | |||
1541 | #define OOB_STATUS 0x14E | ||
1542 | |||
1543 | #define OOB_DONE 0x80 | ||
1544 | #define LOSS_OF_SIGNAL 0x40 /* ro */ | ||
1545 | #define SPINUP_HOLD 0x20 | ||
1546 | #define HOT_PLUG_CNCT 0x10 /* ro */ | ||
1547 | #define GTO_TIMEOUT 0x08 /* ro */ | ||
1548 | #define OOB_TIMEOUT 0x04 /* ro */ | ||
1549 | #define DEVICE_PRESENT 0x02 /* ro */ | ||
1550 | #define OOB_ERROR 0x01 /* ro */ | ||
1551 | |||
1552 | #define OOB_STATUS_ERROR_MASK (LOSS_OF_SIGNAL | GTO_TIMEOUT | \ | ||
1553 | OOB_TIMEOUT | OOB_ERROR) | ||
1554 | |||
1555 | #define OOB_STATUS_CLEAR 0x14F | ||
1556 | |||
1557 | #define OOB_DONE_CLR 0x80 | ||
1558 | #define LOSS_OF_SIGNAL_CLR 0x40 | ||
1559 | #define SPINUP_HOLD_CLR 0x20 | ||
1560 | #define HOT_PLUG_CNCT_CLR 0x10 | ||
1561 | #define GTO_TIMEOUT_CLR 0x08 | ||
1562 | #define OOB_TIMEOUT_CLR 0x04 | ||
1563 | #define OOB_ERROR_CLR 0x01 | ||
1564 | |||
1565 | #define HOT_PLUG_DELAY 0x150 | ||
1566 | /* In 5 ms units. 20 = 100 ms. */ | ||
1567 | #define HOTPLUG_DELAY_TIMEOUT 20 | ||
1568 | |||
1569 | |||
1570 | #define INT_ENABLE_2 0x15A | ||
1571 | |||
1572 | #define OOB_DONE_EN 0x80 | ||
1573 | #define LOSS_OF_SIGNAL_EN 0x40 | ||
1574 | #define SPINUP_HOLD_EN 0x20 | ||
1575 | #define HOT_PLUG_CNCT_EN 0x10 | ||
1576 | #define GTO_TIMEOUT_EN 0x08 | ||
1577 | #define OOB_TIMEOUT_EN 0x04 | ||
1578 | #define DEVICE_PRESENT_EN 0x02 | ||
1579 | #define OOB_ERROR_EN 0x01 | ||
1580 | |||
1581 | #define PHY_CONTROL_0 0x160 | ||
1582 | |||
1583 | #define PHY_LOWPWREN_TX 0x80 | ||
1584 | #define PHY_LOWPWREN_RX 0x40 | ||
1585 | #define SPARE_REG_160_B5 0x20 | ||
1586 | #define OFFSET_CANCEL_RX 0x10 | ||
1587 | |||
1588 | /* bits 3:2 */ | ||
1589 | #define PHY_RXCOMCENTER_60V 0x00 | ||
1590 | #define PHY_RXCOMCENTER_70V 0x04 | ||
1591 | #define PHY_RXCOMCENTER_80V 0x08 | ||
1592 | #define PHY_RXCOMCENTER_90V 0x0C | ||
1593 | #define PHY_RXCOMCENTER_MASK 0x0C | ||
1594 | |||
1595 | #define PHY_RESET 0x02 | ||
1596 | #define SAS_DEFAULT_SEL 0x01 | ||
1597 | |||
1598 | #define PHY_CONTROL_1 0x161 | ||
1599 | |||
1600 | /* bits 2:0 */ | ||
1601 | #define SATA_PHY_DETLEVEL_50mv 0x00 | ||
1602 | #define SATA_PHY_DETLEVEL_75mv 0x01 | ||
1603 | #define SATA_PHY_DETLEVEL_100mv 0x02 | ||
1604 | #define SATA_PHY_DETLEVEL_125mv 0x03 | ||
1605 | #define SATA_PHY_DETLEVEL_150mv 0x04 | ||
1606 | #define SATA_PHY_DETLEVEL_175mv 0x05 | ||
1607 | #define SATA_PHY_DETLEVEL_200mv 0x06 | ||
1608 | #define SATA_PHY_DETLEVEL_225mv 0x07 | ||
1609 | #define SATA_PHY_DETLEVEL_MASK 0x07 | ||
1610 | |||
1611 | /* bits 5:3 */ | ||
1612 | #define SAS_PHY_DETLEVEL_50mv 0x00 | ||
1613 | #define SAS_PHY_DETLEVEL_75mv 0x08 | ||
1614 | #define SAS_PHY_DETLEVEL_100mv 0x10 | ||
1615 | #define SAS_PHY_DETLEVEL_125mv 0x11 | ||
1616 | #define SAS_PHY_DETLEVEL_150mv 0x20 | ||
1617 | #define SAS_PHY_DETLEVEL_175mv 0x21 | ||
1618 | #define SAS_PHY_DETLEVEL_200mv 0x30 | ||
1619 | #define SAS_PHY_DETLEVEL_225mv 0x31 | ||
1620 | #define SAS_PHY_DETLEVEL_MASK 0x38 | ||
1621 | |||
1622 | #define PHY_CONTROL_2 0x162 | ||
1623 | |||
1624 | /* bits 7:5 */ | ||
1625 | #define SATA_PHY_DRV_400mv 0x00 | ||
1626 | #define SATA_PHY_DRV_450mv 0x20 | ||
1627 | #define SATA_PHY_DRV_500mv 0x40 | ||
1628 | #define SATA_PHY_DRV_550mv 0x60 | ||
1629 | #define SATA_PHY_DRV_600mv 0x80 | ||
1630 | #define SATA_PHY_DRV_650mv 0xA0 | ||
1631 | #define SATA_PHY_DRV_725mv 0xC0 | ||
1632 | #define SATA_PHY_DRV_800mv 0xE0 | ||
1633 | #define SATA_PHY_DRV_MASK 0xE0 | ||
1634 | |||
1635 | /* bits 4:3 */ | ||
1636 | #define SATA_PREEMP_0 0x00 | ||
1637 | #define SATA_PREEMP_1 0x08 | ||
1638 | #define SATA_PREEMP_2 0x10 | ||
1639 | #define SATA_PREEMP_3 0x18 | ||
1640 | #define SATA_PREEMP_MASK 0x18 | ||
1641 | |||
1642 | #define SATA_CMSH1P5 0x04 | ||
1643 | |||
1644 | /* bits 1:0 */ | ||
1645 | #define SATA_SLEW_0 0x00 | ||
1646 | #define SATA_SLEW_1 0x01 | ||
1647 | #define SATA_SLEW_2 0x02 | ||
1648 | #define SATA_SLEW_3 0x03 | ||
1649 | #define SATA_SLEW_MASK 0x03 | ||
1650 | |||
1651 | #define PHY_CONTROL_3 0x163 | ||
1652 | |||
1653 | /* bits 7:5 */ | ||
1654 | #define SAS_PHY_DRV_400mv 0x00 | ||
1655 | #define SAS_PHY_DRV_450mv 0x20 | ||
1656 | #define SAS_PHY_DRV_500mv 0x40 | ||
1657 | #define SAS_PHY_DRV_550mv 0x60 | ||
1658 | #define SAS_PHY_DRV_600mv 0x80 | ||
1659 | #define SAS_PHY_DRV_650mv 0xA0 | ||
1660 | #define SAS_PHY_DRV_725mv 0xC0 | ||
1661 | #define SAS_PHY_DRV_800mv 0xE0 | ||
1662 | #define SAS_PHY_DRV_MASK 0xE0 | ||
1663 | |||
1664 | /* bits 4:3 */ | ||
1665 | #define SAS_PREEMP_0 0x00 | ||
1666 | #define SAS_PREEMP_1 0x08 | ||
1667 | #define SAS_PREEMP_2 0x10 | ||
1668 | #define SAS_PREEMP_3 0x18 | ||
1669 | #define SAS_PREEMP_MASK 0x18 | ||
1670 | |||
1671 | #define SAS_CMSH1P5 0x04 | ||
1672 | |||
1673 | /* bits 1:0 */ | ||
1674 | #define SAS_SLEW_0 0x00 | ||
1675 | #define SAS_SLEW_1 0x01 | ||
1676 | #define SAS_SLEW_2 0x02 | ||
1677 | #define SAS_SLEW_3 0x03 | ||
1678 | #define SAS_SLEW_MASK 0x03 | ||
1679 | |||
1680 | #define PHY_CONTROL_4 0x168 | ||
1681 | |||
1682 | #define PHY_DONE_CAL_TX 0x80 | ||
1683 | #define PHY_DONE_CAL_RX 0x40 | ||
1684 | #define RX_TERM_LOAD_DIS 0x20 | ||
1685 | #define TX_TERM_LOAD_DIS 0x10 | ||
1686 | #define AUTO_TERM_CAL_DIS 0x08 | ||
1687 | #define PHY_SIGDET_FLTR_EN 0x04 | ||
1688 | #define OSC_FREQ 0x02 | ||
1689 | #define PHY_START_CAL 0x01 | ||
1690 | |||
1691 | /* | ||
1692 | * HST_PCIX2 Registers, Addresss Range: (0x00-0xFC) | ||
1693 | */ | ||
1694 | #define PCIX_REG_BASE_ADR 0xB8040000 | ||
1695 | |||
1696 | #define PCIC_VENDOR_ID 0x00 | ||
1697 | |||
1698 | #define PCIC_DEVICE_ID 0x02 | ||
1699 | |||
1700 | #define PCIC_COMMAND 0x04 | ||
1701 | |||
1702 | #define INT_DIS 0x0400 | ||
1703 | #define FBB_EN 0x0200 /* ro */ | ||
1704 | #define SERR_EN 0x0100 | ||
1705 | #define STEP_EN 0x0080 /* ro */ | ||
1706 | #define PERR_EN 0x0040 | ||
1707 | #define VGA_EN 0x0020 /* ro */ | ||
1708 | #define MWI_EN 0x0010 | ||
1709 | #define SPC_EN 0x0008 | ||
1710 | #define MST_EN 0x0004 | ||
1711 | #define MEM_EN 0x0002 | ||
1712 | #define IO_EN 0x0001 | ||
1713 | |||
1714 | #define PCIC_STATUS 0x06 | ||
1715 | |||
1716 | #define PERR_DET 0x8000 | ||
1717 | #define SERR_GEN 0x4000 | ||
1718 | #define MABT_DET 0x2000 | ||
1719 | #define TABT_DET 0x1000 | ||
1720 | #define TABT_GEN 0x0800 | ||
1721 | #define DPERR_DET 0x0100 | ||
1722 | #define CAP_LIST 0x0010 | ||
1723 | #define INT_STAT 0x0008 | ||
1724 | |||
1725 | #define PCIC_DEVREV_ID 0x08 | ||
1726 | |||
1727 | #define PCIC_CLASS_CODE 0x09 | ||
1728 | |||
1729 | #define PCIC_CACHELINE_SIZE 0x0C | ||
1730 | |||
1731 | #define PCIC_MBAR0 0x10 | ||
1732 | |||
1733 | #define PCIC_MBAR0_OFFSET 0 | ||
1734 | |||
1735 | #define PCIC_MBAR1 0x18 | ||
1736 | |||
1737 | #define PCIC_MBAR1_OFFSET 2 | ||
1738 | |||
1739 | #define PCIC_IOBAR 0x20 | ||
1740 | |||
1741 | #define PCIC_IOBAR_OFFSET 4 | ||
1742 | |||
1743 | #define PCIC_SUBVENDOR_ID 0x2C | ||
1744 | |||
1745 | #define PCIC_SUBSYTEM_ID 0x2E | ||
1746 | |||
1747 | #define PCIX_STATUS 0x44 | ||
1748 | #define RCV_SCE 0x20000000 | ||
1749 | #define UNEXP_SC 0x00080000 | ||
1750 | #define SC_DISCARD 0x00040000 | ||
1751 | |||
1752 | #define ECC_CTRL_STAT 0x48 | ||
1753 | #define UNCOR_ECCERR 0x00000008 | ||
1754 | |||
1755 | #define PCIC_PM_CSR 0x5C | ||
1756 | |||
1757 | #define PWR_STATE_D0 0 | ||
1758 | #define PWR_STATE_D1 1 /* not supported */ | ||
1759 | #define PWR_STATE_D2 2 /* not supported */ | ||
1760 | #define PWR_STATE_D3 3 | ||
1761 | |||
1762 | #define PCIC_BASE1 0x6C /* internal use only */ | ||
1763 | |||
1764 | #define BASE1_RSVD 0xFFFFFFF8 | ||
1765 | |||
1766 | #define PCIC_BASEA 0x70 /* internal use only */ | ||
1767 | |||
1768 | #define BASEA_RSVD 0xFFFFFFC0 | ||
1769 | #define BASEA_START 0 | ||
1770 | |||
1771 | #define PCIC_BASEB 0x74 /* internal use only */ | ||
1772 | |||
1773 | #define BASEB_RSVD 0xFFFFFF80 | ||
1774 | #define BASEB_IOMAP_MASK 0x7F | ||
1775 | #define BASEB_START 0x80 | ||
1776 | |||
1777 | #define PCIC_BASEC 0x78 /* internal use only */ | ||
1778 | |||
1779 | #define BASEC_RSVD 0xFFFFFFFC | ||
1780 | #define BASEC_MASK 0x03 | ||
1781 | #define BASEC_START 0x58 | ||
1782 | |||
1783 | #define PCIC_MBAR_KEY 0x7C /* internal use only */ | ||
1784 | |||
1785 | #define MBAR_KEY_MASK 0xFFFFFFFF | ||
1786 | |||
1787 | #define PCIC_HSTPCIX_CNTRL 0xA0 | ||
1788 | |||
1789 | #define REWIND_DIS 0x0800 | ||
1790 | #define SC_TMR_DIS 0x04000000 | ||
1791 | |||
1792 | #define PCIC_MBAR0_MASK 0xA8 | ||
1793 | #define PCIC_MBAR0_SIZE_MASK 0x1FFFE000 | ||
1794 | #define PCIC_MBAR0_SIZE_SHIFT 13 | ||
1795 | #define PCIC_MBAR0_SIZE(val) \ | ||
1796 | (((val) & PCIC_MBAR0_SIZE_MASK) >> PCIC_MBAR0_SIZE_SHIFT) | ||
1797 | |||
1798 | #define PCIC_FLASH_MBAR 0xB8 | ||
1799 | |||
1800 | #define PCIC_INTRPT_STAT 0xD4 | ||
1801 | |||
1802 | #define PCIC_TP_CTRL 0xFC | ||
1803 | |||
1804 | /* | ||
1805 | * EXSI Registers, Addresss Range: (0x00-0xFC) | ||
1806 | */ | ||
1807 | #define EXSI_REG_BASE_ADR REG_BASE_ADDR_EXSI | ||
1808 | |||
1809 | #define EXSICNFGR (EXSI_REG_BASE_ADR + 0x00) | ||
1810 | |||
1811 | #define OCMINITIALIZED 0x80000000 | ||
1812 | #define ASIEN 0x00400000 | ||
1813 | #define HCMODE 0x00200000 | ||
1814 | #define PCIDEF 0x00100000 | ||
1815 | #define COMSTOCK 0x00080000 | ||
1816 | #define SEEPROMEND 0x00040000 | ||
1817 | #define MSTTIMEN 0x00020000 | ||
1818 | #define XREGEX 0x00000200 | ||
1819 | #define NVRAMW 0x00000100 | ||
1820 | #define NVRAMEX 0x00000080 | ||
1821 | #define SRAMW 0x00000040 | ||
1822 | #define SRAMEX 0x00000020 | ||
1823 | #define FLASHW 0x00000010 | ||
1824 | #define FLASHEX 0x00000008 | ||
1825 | #define SEEPROMCFG 0x00000004 | ||
1826 | #define SEEPROMTYP 0x00000002 | ||
1827 | #define SEEPROMEX 0x00000001 | ||
1828 | |||
1829 | |||
1830 | #define EXSICNTRLR (EXSI_REG_BASE_ADR + 0x04) | ||
1831 | |||
1832 | #define MODINT_EN 0x00000001 | ||
1833 | |||
1834 | |||
1835 | #define PMSTATR (EXSI_REG_BASE_ADR + 0x10) | ||
1836 | |||
1837 | #define FLASHRST 0x00000002 | ||
1838 | #define FLASHRDY 0x00000001 | ||
1839 | |||
1840 | |||
1841 | #define FLCNFGR (EXSI_REG_BASE_ADR + 0x14) | ||
1842 | |||
1843 | #define FLWEH_MASK 0x30000000 | ||
1844 | #define FLWESU_MASK 0x0C000000 | ||
1845 | #define FLWEPW_MASK 0x03F00000 | ||
1846 | #define FLOEH_MASK 0x000C0000 | ||
1847 | #define FLOESU_MASK 0x00030000 | ||
1848 | #define FLOEPW_MASK 0x0000FC00 | ||
1849 | #define FLCSH_MASK 0x00000300 | ||
1850 | #define FLCSSU_MASK 0x000000C0 | ||
1851 | #define FLCSPW_MASK 0x0000003F | ||
1852 | |||
1853 | #define SRCNFGR (EXSI_REG_BASE_ADR + 0x18) | ||
1854 | |||
1855 | #define SRWEH_MASK 0x30000000 | ||
1856 | #define SRWESU_MASK 0x0C000000 | ||
1857 | #define SRWEPW_MASK 0x03F00000 | ||
1858 | |||
1859 | #define SROEH_MASK 0x000C0000 | ||
1860 | #define SROESU_MASK 0x00030000 | ||
1861 | #define SROEPW_MASK 0x0000FC00 | ||
1862 | #define SRCSH_MASK 0x00000300 | ||
1863 | #define SRCSSU_MASK 0x000000C0 | ||
1864 | #define SRCSPW_MASK 0x0000003F | ||
1865 | |||
1866 | #define NVCNFGR (EXSI_REG_BASE_ADR + 0x1C) | ||
1867 | |||
1868 | #define NVWEH_MASK 0x30000000 | ||
1869 | #define NVWESU_MASK 0x0C000000 | ||
1870 | #define NVWEPW_MASK 0x03F00000 | ||
1871 | #define NVOEH_MASK 0x000C0000 | ||
1872 | #define NVOESU_MASK 0x00030000 | ||
1873 | #define NVOEPW_MASK 0x0000FC00 | ||
1874 | #define NVCSH_MASK 0x00000300 | ||
1875 | #define NVCSSU_MASK 0x000000C0 | ||
1876 | #define NVCSPW_MASK 0x0000003F | ||
1877 | |||
1878 | #define XRCNFGR (EXSI_REG_BASE_ADR + 0x20) | ||
1879 | |||
1880 | #define XRWEH_MASK 0x30000000 | ||
1881 | #define XRWESU_MASK 0x0C000000 | ||
1882 | #define XRWEPW_MASK 0x03F00000 | ||
1883 | #define XROEH_MASK 0x000C0000 | ||
1884 | #define XROESU_MASK 0x00030000 | ||
1885 | #define XROEPW_MASK 0x0000FC00 | ||
1886 | #define XRCSH_MASK 0x00000300 | ||
1887 | #define XRCSSU_MASK 0x000000C0 | ||
1888 | #define XRCSPW_MASK 0x0000003F | ||
1889 | |||
1890 | #define XREGADDR (EXSI_REG_BASE_ADR + 0x24) | ||
1891 | |||
1892 | #define XRADDRINCEN 0x80000000 | ||
1893 | #define XREGADD_MASK 0x007FFFFF | ||
1894 | |||
1895 | |||
1896 | #define XREGDATAR (EXSI_REG_BASE_ADR + 0x28) | ||
1897 | |||
1898 | #define XREGDATA_MASK 0x0000FFFF | ||
1899 | |||
1900 | #define GPIOOER (EXSI_REG_BASE_ADR + 0x40) | ||
1901 | |||
1902 | #define GPIOODENR (EXSI_REG_BASE_ADR + 0x44) | ||
1903 | |||
1904 | #define GPIOINVR (EXSI_REG_BASE_ADR + 0x48) | ||
1905 | |||
1906 | #define GPIODATAOR (EXSI_REG_BASE_ADR + 0x4C) | ||
1907 | |||
1908 | #define GPIODATAIR (EXSI_REG_BASE_ADR + 0x50) | ||
1909 | |||
1910 | #define GPIOCNFGR (EXSI_REG_BASE_ADR + 0x54) | ||
1911 | |||
1912 | #define GPIO_EXTSRC 0x00000001 | ||
1913 | |||
1914 | #define SCNTRLR (EXSI_REG_BASE_ADR + 0xA0) | ||
1915 | |||
1916 | #define SXFERDONE 0x00000100 | ||
1917 | #define SXFERCNT_MASK 0x000000E0 | ||
1918 | #define SCMDTYP_MASK 0x0000001C | ||
1919 | #define SXFERSTART 0x00000002 | ||
1920 | #define SXFEREN 0x00000001 | ||
1921 | |||
1922 | #define SRATER (EXSI_REG_BASE_ADR + 0xA4) | ||
1923 | |||
1924 | #define SADDRR (EXSI_REG_BASE_ADR + 0xA8) | ||
1925 | |||
1926 | #define SADDR_MASK 0x0000FFFF | ||
1927 | |||
1928 | #define SDATAOR (EXSI_REG_BASE_ADR + 0xAC) | ||
1929 | |||
1930 | #define SDATAOR0 (EXSI_REG_BASE_ADR + 0xAC) | ||
1931 | #define SDATAOR1 (EXSI_REG_BASE_ADR + 0xAD) | ||
1932 | #define SDATAOR2 (EXSI_REG_BASE_ADR + 0xAE) | ||
1933 | #define SDATAOR3 (EXSI_REG_BASE_ADR + 0xAF) | ||
1934 | |||
1935 | #define SDATAIR (EXSI_REG_BASE_ADR + 0xB0) | ||
1936 | |||
1937 | #define SDATAIR0 (EXSI_REG_BASE_ADR + 0xB0) | ||
1938 | #define SDATAIR1 (EXSI_REG_BASE_ADR + 0xB1) | ||
1939 | #define SDATAIR2 (EXSI_REG_BASE_ADR + 0xB2) | ||
1940 | #define SDATAIR3 (EXSI_REG_BASE_ADR + 0xB3) | ||
1941 | |||
1942 | #define ASISTAT0R (EXSI_REG_BASE_ADR + 0xD0) | ||
1943 | #define ASIFMTERR 0x00000400 | ||
1944 | #define ASISEECHKERR 0x00000200 | ||
1945 | #define ASIERR 0x00000100 | ||
1946 | |||
1947 | #define ASISTAT1R (EXSI_REG_BASE_ADR + 0xD4) | ||
1948 | #define CHECKSUM_MASK 0x0000FFFF | ||
1949 | |||
1950 | #define ASIERRADDR (EXSI_REG_BASE_ADR + 0xD8) | ||
1951 | #define ASIERRDATAR (EXSI_REG_BASE_ADR + 0xDC) | ||
1952 | #define ASIERRSTATR (EXSI_REG_BASE_ADR + 0xE0) | ||
1953 | #define CPI2ASIBYTECNT_MASK 0x00070000 | ||
1954 | #define CPI2ASIBYTEEN_MASK 0x0000F000 | ||
1955 | #define CPI2ASITARGERR_MASK 0x00000F00 | ||
1956 | #define CPI2ASITARGMID_MASK 0x000000F0 | ||
1957 | #define CPI2ASIMSTERR_MASK 0x0000000F | ||
1958 | |||
1959 | /* | ||
1960 | * XSRAM, External SRAM (DWord and any BE pattern accessible) | ||
1961 | */ | ||
1962 | #define XSRAM_REG_BASE_ADDR 0xB8100000 | ||
1963 | #define XSRAM_SIZE 0x100000 | ||
1964 | |||
1965 | /* | ||
1966 | * NVRAM Registers, Address Range: (0x00000 - 0x3FFFF). | ||
1967 | */ | ||
1968 | #define NVRAM_REG_BASE_ADR 0xBF800000 | ||
1969 | #define NVRAM_MAX_BASE_ADR 0x003FFFFF | ||
1970 | |||
1971 | /* OCM base address */ | ||
1972 | #define OCM_BASE_ADDR 0xA0000000 | ||
1973 | #define OCM_MAX_SIZE 0x20000 | ||
1974 | |||
1975 | /* | ||
1976 | * Sequencers (Central and Link) Scratch RAM page definitions. | ||
1977 | */ | ||
1978 | |||
1979 | /* | ||
1980 | * The Central Management Sequencer (CSEQ) Scratch Memory is a 1024 | ||
1981 | * byte memory. It is dword accessible and has byte parity | ||
1982 | * protection. The CSEQ accesses it in 32 byte windows, either as mode | ||
1983 | * dependent or mode independent memory. Each mode has 96 bytes, | ||
1984 | * (three 32 byte pages 0-2, not contiguous), leaving 128 bytes of | ||
1985 | * Mode Independent memory (four 32 byte pages 3-7). Note that mode | ||
1986 | * dependent scratch memory, Mode 8, page 0-3 overlaps mode | ||
1987 | * independent scratch memory, pages 0-3. | ||
1988 | * - 896 bytes of mode dependent scratch, 96 bytes per Modes 0-7, and | ||
1989 | * 128 bytes in mode 8, | ||
1990 | * - 259 bytes of mode independent scratch, common to modes 0-15. | ||
1991 | * | ||
1992 | * Sequencer scratch RAM is 1024 bytes. This scratch memory is | ||
1993 | * divided into mode dependent and mode independent scratch with this | ||
1994 | * memory further subdivided into pages of size 32 bytes. There are 5 | ||
1995 | * pages (160 bytes) of mode independent scratch and 3 pages of | ||
1996 | * dependent scratch memory for modes 0-7 (768 bytes). Mode 8 pages | ||
1997 | * 0-2 dependent scratch overlap with pages 0-2 of mode independent | ||
1998 | * scratch memory. | ||
1999 | * | ||
2000 | * The host accesses this scratch in a different manner from the | ||
2001 | * central sequencer. The sequencer has to use CSEQ registers CSCRPAGE | ||
2002 | * and CMnSCRPAGE to access the scratch memory. A flat mapping of the | ||
2003 | * scratch memory is avaliable for software convenience and to prevent | ||
2004 | * corruption while the sequencer is running. This memory is mapped | ||
2005 | * onto addresses 800h - BFFh, total of 400h bytes. | ||
2006 | * | ||
2007 | * These addresses are mapped as follows: | ||
2008 | * | ||
2009 | * 800h-83Fh Mode Dependent Scratch Mode 0 Pages 0-1 | ||
2010 | * 840h-87Fh Mode Dependent Scratch Mode 1 Pages 0-1 | ||
2011 | * 880h-8BFh Mode Dependent Scratch Mode 2 Pages 0-1 | ||
2012 | * 8C0h-8FFh Mode Dependent Scratch Mode 3 Pages 0-1 | ||
2013 | * 900h-93Fh Mode Dependent Scratch Mode 4 Pages 0-1 | ||
2014 | * 940h-97Fh Mode Dependent Scratch Mode 5 Pages 0-1 | ||
2015 | * 980h-9BFh Mode Dependent Scratch Mode 6 Pages 0-1 | ||
2016 | * 9C0h-9FFh Mode Dependent Scratch Mode 7 Pages 0-1 | ||
2017 | * A00h-A5Fh Mode Dependent Scratch Mode 8 Pages 0-2 | ||
2018 | * Mode Independent Scratch Pages 0-2 | ||
2019 | * A60h-A7Fh Mode Dependent Scratch Mode 8 Page 3 | ||
2020 | * Mode Independent Scratch Page 3 | ||
2021 | * A80h-AFFh Mode Independent Scratch Pages 4-7 | ||
2022 | * B00h-B1Fh Mode Dependent Scratch Mode 0 Page 2 | ||
2023 | * B20h-B3Fh Mode Dependent Scratch Mode 1 Page 2 | ||
2024 | * B40h-B5Fh Mode Dependent Scratch Mode 2 Page 2 | ||
2025 | * B60h-B7Fh Mode Dependent Scratch Mode 3 Page 2 | ||
2026 | * B80h-B9Fh Mode Dependent Scratch Mode 4 Page 2 | ||
2027 | * BA0h-BBFh Mode Dependent Scratch Mode 5 Page 2 | ||
2028 | * BC0h-BDFh Mode Dependent Scratch Mode 6 Page 2 | ||
2029 | * BE0h-BFFh Mode Dependent Scratch Mode 7 Page 2 | ||
2030 | */ | ||
2031 | |||
2032 | /* General macros */ | ||
2033 | #define CSEQ_PAGE_SIZE 32 /* Scratch page size (in bytes) */ | ||
2034 | |||
2035 | /* All macros start with offsets from base + 0x800 (CMAPPEDSCR). | ||
2036 | * Mode dependent scratch page 0, mode 0. | ||
2037 | * For modes 1-7 you have to do arithmetic. */ | ||
2038 | #define CSEQ_LRM_SAVE_SINDEX (CMAPPEDSCR + 0x0000) | ||
2039 | #define CSEQ_LRM_SAVE_SCBPTR (CMAPPEDSCR + 0x0002) | ||
2040 | #define CSEQ_Q_LINK_HEAD (CMAPPEDSCR + 0x0004) | ||
2041 | #define CSEQ_Q_LINK_TAIL (CMAPPEDSCR + 0x0006) | ||
2042 | #define CSEQ_LRM_SAVE_SCRPAGE (CMAPPEDSCR + 0x0008) | ||
2043 | |||
2044 | /* Mode dependent scratch page 0 mode 8 macros. */ | ||
2045 | #define CSEQ_RET_ADDR (CMAPPEDSCR + 0x0200) | ||
2046 | #define CSEQ_RET_SCBPTR (CMAPPEDSCR + 0x0202) | ||
2047 | #define CSEQ_SAVE_SCBPTR (CMAPPEDSCR + 0x0204) | ||
2048 | #define CSEQ_EMPTY_TRANS_CTX (CMAPPEDSCR + 0x0206) | ||
2049 | #define CSEQ_RESP_LEN (CMAPPEDSCR + 0x0208) | ||
2050 | #define CSEQ_TMF_SCBPTR (CMAPPEDSCR + 0x020A) | ||
2051 | #define CSEQ_GLOBAL_PREV_SCB (CMAPPEDSCR + 0x020C) | ||
2052 | #define CSEQ_GLOBAL_HEAD (CMAPPEDSCR + 0x020E) | ||
2053 | #define CSEQ_CLEAR_LU_HEAD (CMAPPEDSCR + 0x0210) | ||
2054 | #define CSEQ_TMF_OPCODE (CMAPPEDSCR + 0x0212) | ||
2055 | #define CSEQ_SCRATCH_FLAGS (CMAPPEDSCR + 0x0213) | ||
2056 | #define CSEQ_HSB_SITE (CMAPPEDSCR + 0x021A) | ||
2057 | #define CSEQ_FIRST_INV_SCB_SITE (CMAPPEDSCR + 0x021C) | ||
2058 | #define CSEQ_FIRST_INV_DDB_SITE (CMAPPEDSCR + 0x021E) | ||
2059 | |||
2060 | /* Mode dependent scratch page 1 mode 8 macros. */ | ||
2061 | #define CSEQ_LUN_TO_CLEAR (CMAPPEDSCR + 0x0220) | ||
2062 | #define CSEQ_LUN_TO_CHECK (CMAPPEDSCR + 0x0228) | ||
2063 | |||
2064 | /* Mode dependent scratch page 2 mode 8 macros */ | ||
2065 | #define CSEQ_HQ_NEW_POINTER (CMAPPEDSCR + 0x0240) | ||
2066 | #define CSEQ_HQ_DONE_BASE (CMAPPEDSCR + 0x0248) | ||
2067 | #define CSEQ_HQ_DONE_POINTER (CMAPPEDSCR + 0x0250) | ||
2068 | #define CSEQ_HQ_DONE_PASS (CMAPPEDSCR + 0x0254) | ||
2069 | |||
2070 | /* Mode independent scratch page 4 macros. */ | ||
2071 | #define CSEQ_Q_EXE_HEAD (CMAPPEDSCR + 0x0280) | ||
2072 | #define CSEQ_Q_EXE_TAIL (CMAPPEDSCR + 0x0282) | ||
2073 | #define CSEQ_Q_DONE_HEAD (CMAPPEDSCR + 0x0284) | ||
2074 | #define CSEQ_Q_DONE_TAIL (CMAPPEDSCR + 0x0286) | ||
2075 | #define CSEQ_Q_SEND_HEAD (CMAPPEDSCR + 0x0288) | ||
2076 | #define CSEQ_Q_SEND_TAIL (CMAPPEDSCR + 0x028A) | ||
2077 | #define CSEQ_Q_DMA2CHIM_HEAD (CMAPPEDSCR + 0x028C) | ||
2078 | #define CSEQ_Q_DMA2CHIM_TAIL (CMAPPEDSCR + 0x028E) | ||
2079 | #define CSEQ_Q_COPY_HEAD (CMAPPEDSCR + 0x0290) | ||
2080 | #define CSEQ_Q_COPY_TAIL (CMAPPEDSCR + 0x0292) | ||
2081 | #define CSEQ_REG0 (CMAPPEDSCR + 0x0294) | ||
2082 | #define CSEQ_REG1 (CMAPPEDSCR + 0x0296) | ||
2083 | #define CSEQ_REG2 (CMAPPEDSCR + 0x0298) | ||
2084 | #define CSEQ_LINK_CTL_Q_MAP (CMAPPEDSCR + 0x029C) | ||
2085 | #define CSEQ_MAX_CSEQ_MODE (CMAPPEDSCR + 0x029D) | ||
2086 | #define CSEQ_FREE_LIST_HACK_COUNT (CMAPPEDSCR + 0x029E) | ||
2087 | |||
2088 | /* Mode independent scratch page 5 macros. */ | ||
2089 | #define CSEQ_EST_NEXUS_REQ_QUEUE (CMAPPEDSCR + 0x02A0) | ||
2090 | #define CSEQ_EST_NEXUS_REQ_COUNT (CMAPPEDSCR + 0x02A8) | ||
2091 | #define CSEQ_Q_EST_NEXUS_HEAD (CMAPPEDSCR + 0x02B0) | ||
2092 | #define CSEQ_Q_EST_NEXUS_TAIL (CMAPPEDSCR + 0x02B2) | ||
2093 | #define CSEQ_NEED_EST_NEXUS_SCB (CMAPPEDSCR + 0x02B4) | ||
2094 | #define CSEQ_EST_NEXUS_REQ_HEAD (CMAPPEDSCR + 0x02B6) | ||
2095 | #define CSEQ_EST_NEXUS_REQ_TAIL (CMAPPEDSCR + 0x02B7) | ||
2096 | #define CSEQ_EST_NEXUS_SCB_OFFSET (CMAPPEDSCR + 0x02B8) | ||
2097 | |||
2098 | /* Mode independent scratch page 6 macros. */ | ||
2099 | #define CSEQ_INT_ROUT_RET_ADDR0 (CMAPPEDSCR + 0x02C0) | ||
2100 | #define CSEQ_INT_ROUT_RET_ADDR1 (CMAPPEDSCR + 0x02C2) | ||
2101 | #define CSEQ_INT_ROUT_SCBPTR (CMAPPEDSCR + 0x02C4) | ||
2102 | #define CSEQ_INT_ROUT_MODE (CMAPPEDSCR + 0x02C6) | ||
2103 | #define CSEQ_ISR_SCRATCH_FLAGS (CMAPPEDSCR + 0x02C7) | ||
2104 | #define CSEQ_ISR_SAVE_SINDEX (CMAPPEDSCR + 0x02C8) | ||
2105 | #define CSEQ_ISR_SAVE_DINDEX (CMAPPEDSCR + 0x02CA) | ||
2106 | #define CSEQ_Q_MONIRTT_HEAD (CMAPPEDSCR + 0x02D0) | ||
2107 | #define CSEQ_Q_MONIRTT_TAIL (CMAPPEDSCR + 0x02D2) | ||
2108 | #define CSEQ_FREE_SCB_MASK (CMAPPEDSCR + 0x02D5) | ||
2109 | #define CSEQ_BUILTIN_FREE_SCB_HEAD (CMAPPEDSCR + 0x02D6) | ||
2110 | #define CSEQ_BUILTIN_FREE_SCB_TAIL (CMAPPEDSCR + 0x02D8) | ||
2111 | #define CSEQ_EXTENDED_FREE_SCB_HEAD (CMAPPEDSCR + 0x02DA) | ||
2112 | #define CSEQ_EXTENDED_FREE_SCB_TAIL (CMAPPEDSCR + 0x02DC) | ||
2113 | |||
2114 | /* Mode independent scratch page 7 macros. */ | ||
2115 | #define CSEQ_EMPTY_REQ_QUEUE (CMAPPEDSCR + 0x02E0) | ||
2116 | #define CSEQ_EMPTY_REQ_COUNT (CMAPPEDSCR + 0x02E8) | ||
2117 | #define CSEQ_Q_EMPTY_HEAD (CMAPPEDSCR + 0x02F0) | ||
2118 | #define CSEQ_Q_EMPTY_TAIL (CMAPPEDSCR + 0x02F2) | ||
2119 | #define CSEQ_NEED_EMPTY_SCB (CMAPPEDSCR + 0x02F4) | ||
2120 | #define CSEQ_EMPTY_REQ_HEAD (CMAPPEDSCR + 0x02F6) | ||
2121 | #define CSEQ_EMPTY_REQ_TAIL (CMAPPEDSCR + 0x02F7) | ||
2122 | #define CSEQ_EMPTY_SCB_OFFSET (CMAPPEDSCR + 0x02F8) | ||
2123 | #define CSEQ_PRIMITIVE_DATA (CMAPPEDSCR + 0x02FA) | ||
2124 | #define CSEQ_TIMEOUT_CONST (CMAPPEDSCR + 0x02FC) | ||
2125 | |||
2126 | /*************************************************************************** | ||
2127 | * Link m Sequencer scratch RAM is 512 bytes. | ||
2128 | * This scratch memory is divided into mode dependent and mode | ||
2129 | * independent scratch with this memory further subdivided into | ||
2130 | * pages of size 32 bytes. There are 4 pages (128 bytes) of | ||
2131 | * mode independent scratch and 4 pages of dependent scratch | ||
2132 | * memory for modes 0-2 (384 bytes). | ||
2133 | * | ||
2134 | * The host accesses this scratch in a different manner from the | ||
2135 | * link sequencer. The sequencer has to use LSEQ registers | ||
2136 | * LmSCRPAGE and LmMnSCRPAGE to access the scratch memory. A flat | ||
2137 | * mapping of the scratch memory is avaliable for software | ||
2138 | * convenience and to prevent corruption while the sequencer is | ||
2139 | * running. This memory is mapped onto addresses 800h - 9FFh. | ||
2140 | * | ||
2141 | * These addresses are mapped as follows: | ||
2142 | * | ||
2143 | * 800h-85Fh Mode Dependent Scratch Mode 0 Pages 0-2 | ||
2144 | * 860h-87Fh Mode Dependent Scratch Mode 0 Page 3 | ||
2145 | * Mode Dependent Scratch Mode 5 Page 0 | ||
2146 | * 880h-8DFh Mode Dependent Scratch Mode 1 Pages 0-2 | ||
2147 | * 8E0h-8FFh Mode Dependent Scratch Mode 1 Page 3 | ||
2148 | * Mode Dependent Scratch Mode 5 Page 1 | ||
2149 | * 900h-95Fh Mode Dependent Scratch Mode 2 Pages 0-2 | ||
2150 | * 960h-97Fh Mode Dependent Scratch Mode 2 Page 3 | ||
2151 | * Mode Dependent Scratch Mode 5 Page 2 | ||
2152 | * 980h-9DFh Mode Independent Scratch Pages 0-3 | ||
2153 | * 9E0h-9FFh Mode Independent Scratch Page 3 | ||
2154 | * Mode Dependent Scratch Mode 5 Page 3 | ||
2155 | * | ||
2156 | ****************************************************************************/ | ||
2157 | /* General macros */ | ||
2158 | #define LSEQ_MODE_SCRATCH_SIZE 0x80 /* Size of scratch RAM per mode */ | ||
2159 | #define LSEQ_PAGE_SIZE 0x20 /* Scratch page size (in bytes) */ | ||
2160 | #define LSEQ_MODE5_PAGE0_OFFSET 0x60 | ||
2161 | |||
2162 | /* Common mode dependent scratch page 0 macros for modes 0,1,2, and 5 */ | ||
2163 | /* Indexed using LSEQ_MODE_SCRATCH_SIZE * mode, for modes 0,1,2. */ | ||
2164 | #define LmSEQ_RET_ADDR(LinkNum) (LmSCRATCH(LinkNum) + 0x0000) | ||
2165 | #define LmSEQ_REG0_MODE(LinkNum) (LmSCRATCH(LinkNum) + 0x0002) | ||
2166 | #define LmSEQ_MODE_FLAGS(LinkNum) (LmSCRATCH(LinkNum) + 0x0004) | ||
2167 | |||
2168 | /* Mode flag macros (byte 0) */ | ||
2169 | #define SAS_SAVECTX_OCCURRED 0x80 | ||
2170 | #define SAS_OOBSVC_OCCURRED 0x40 | ||
2171 | #define SAS_OOB_DEVICE_PRESENT 0x20 | ||
2172 | #define SAS_CFGHDR_OCCURRED 0x10 | ||
2173 | #define SAS_RCV_INTS_ARE_DISABLED 0x08 | ||
2174 | #define SAS_OOB_HOT_PLUG_CNCT 0x04 | ||
2175 | #define SAS_AWAIT_OPEN_CONNECTION 0x02 | ||
2176 | #define SAS_CFGCMPLT_OCCURRED 0x01 | ||
2177 | |||
2178 | /* Mode flag macros (byte 1) */ | ||
2179 | #define SAS_RLSSCB_OCCURRED 0x80 | ||
2180 | #define SAS_FORCED_HEADER_MISS 0x40 | ||
2181 | |||
2182 | #define LmSEQ_RET_ADDR2(LinkNum) (LmSCRATCH(LinkNum) + 0x0006) | ||
2183 | #define LmSEQ_RET_ADDR1(LinkNum) (LmSCRATCH(LinkNum) + 0x0008) | ||
2184 | #define LmSEQ_OPCODE_TO_CSEQ(LinkNum) (LmSCRATCH(LinkNum) + 0x000B) | ||
2185 | #define LmSEQ_DATA_TO_CSEQ(LinkNum) (LmSCRATCH(LinkNum) + 0x000C) | ||
2186 | |||
2187 | /* Mode dependent scratch page 0 macros for mode 0 (non-common) */ | ||
2188 | /* Absolute offsets */ | ||
2189 | #define LmSEQ_FIRST_INV_DDB_SITE(LinkNum) (LmSCRATCH(LinkNum) + 0x000E) | ||
2190 | #define LmSEQ_EMPTY_TRANS_CTX(LinkNum) (LmSCRATCH(LinkNum) + 0x0010) | ||
2191 | #define LmSEQ_RESP_LEN(LinkNum) (LmSCRATCH(LinkNum) + 0x0012) | ||
2192 | #define LmSEQ_FIRST_INV_SCB_SITE(LinkNum) (LmSCRATCH(LinkNum) + 0x0014) | ||
2193 | #define LmSEQ_INTEN_SAVE(LinkNum) (LmSCRATCH(LinkNum) + 0x0016) | ||
2194 | #define LmSEQ_LINK_RST_FRM_LEN(LinkNum) (LmSCRATCH(LinkNum) + 0x001A) | ||
2195 | #define LmSEQ_LINK_RST_PROTOCOL(LinkNum) (LmSCRATCH(LinkNum) + 0x001B) | ||
2196 | #define LmSEQ_RESP_STATUS(LinkNum) (LmSCRATCH(LinkNum) + 0x001C) | ||
2197 | #define LmSEQ_LAST_LOADED_SGE(LinkNum) (LmSCRATCH(LinkNum) + 0x001D) | ||
2198 | #define LmSEQ_SAVE_SCBPTR(LinkNum) (LmSCRATCH(LinkNum) + 0x001E) | ||
2199 | |||
2200 | /* Mode dependent scratch page 0 macros for mode 1 (non-common) */ | ||
2201 | /* Absolute offsets */ | ||
2202 | #define LmSEQ_Q_XMIT_HEAD(LinkNum) (LmSCRATCH(LinkNum) + 0x008E) | ||
2203 | #define LmSEQ_M1_EMPTY_TRANS_CTX(LinkNum) (LmSCRATCH(LinkNum) + 0x0090) | ||
2204 | #define LmSEQ_INI_CONN_TAG(LinkNum) (LmSCRATCH(LinkNum) + 0x0092) | ||
2205 | #define LmSEQ_FAILED_OPEN_STATUS(LinkNum) (LmSCRATCH(LinkNum) + 0x009A) | ||
2206 | #define LmSEQ_XMIT_REQUEST_TYPE(LinkNum) (LmSCRATCH(LinkNum) + 0x009B) | ||
2207 | #define LmSEQ_M1_RESP_STATUS(LinkNum) (LmSCRATCH(LinkNum) + 0x009C) | ||
2208 | #define LmSEQ_M1_LAST_LOADED_SGE(LinkNum) (LmSCRATCH(LinkNum) + 0x009D) | ||
2209 | #define LmSEQ_M1_SAVE_SCBPTR(LinkNum) (LmSCRATCH(LinkNum) + 0x009E) | ||
2210 | |||
2211 | /* Mode dependent scratch page 0 macros for mode 2 (non-common) */ | ||
2212 | #define LmSEQ_PORT_COUNTER(LinkNum) (LmSCRATCH(LinkNum) + 0x010E) | ||
2213 | #define LmSEQ_PM_TABLE_PTR(LinkNum) (LmSCRATCH(LinkNum) + 0x0110) | ||
2214 | #define LmSEQ_SATA_INTERLOCK_TMR_SAVE(LinkNum) (LmSCRATCH(LinkNum) + 0x0112) | ||
2215 | #define LmSEQ_IP_BITL(LinkNum) (LmSCRATCH(LinkNum) + 0x0114) | ||
2216 | #define LmSEQ_COPY_SMP_CONN_TAG(LinkNum) (LmSCRATCH(LinkNum) + 0x0116) | ||
2217 | #define LmSEQ_P0M2_OFFS1AH(LinkNum) (LmSCRATCH(LinkNum) + 0x011A) | ||
2218 | |||
2219 | /* Mode dependent scratch page 0 macros for modes 4/5 (non-common) */ | ||
2220 | /* Absolute offsets */ | ||
2221 | #define LmSEQ_SAVED_OOB_STATUS(LinkNum) (LmSCRATCH(LinkNum) + 0x006E) | ||
2222 | #define LmSEQ_SAVED_OOB_MODE(LinkNum) (LmSCRATCH(LinkNum) + 0x006F) | ||
2223 | #define LmSEQ_Q_LINK_HEAD(LinkNum) (LmSCRATCH(LinkNum) + 0x0070) | ||
2224 | #define LmSEQ_LINK_RST_ERR(LinkNum) (LmSCRATCH(LinkNum) + 0x0072) | ||
2225 | #define LmSEQ_SAVED_OOB_SIGNALS(LinkNum) (LmSCRATCH(LinkNum) + 0x0073) | ||
2226 | #define LmSEQ_SAS_RESET_MODE(LinkNum) (LmSCRATCH(LinkNum) + 0x0074) | ||
2227 | #define LmSEQ_LINK_RESET_RETRY_COUNT(LinkNum) (LmSCRATCH(LinkNum) + 0x0075) | ||
2228 | #define LmSEQ_NUM_LINK_RESET_RETRIES(LinkNum) (LmSCRATCH(LinkNum) + 0x0076) | ||
2229 | #define LmSEQ_OOB_INT_ENABLES(LinkNum) (LmSCRATCH(LinkNum) + 0x007A) | ||
2230 | #define LmSEQ_NOTIFY_TIMER_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x007C) | ||
2231 | #define LmSEQ_NOTIFY_TIMER_DOWN_COUNT(LinkNum) (LmSCRATCH(LinkNum) + 0x007E) | ||
2232 | |||
2233 | /* Mode dependent scratch page 1, mode 0 and mode 1 */ | ||
2234 | #define LmSEQ_SG_LIST_PTR_ADDR0(LinkNum) (LmSCRATCH(LinkNum) + 0x0020) | ||
2235 | #define LmSEQ_SG_LIST_PTR_ADDR1(LinkNum) (LmSCRATCH(LinkNum) + 0x0030) | ||
2236 | #define LmSEQ_M1_SG_LIST_PTR_ADDR0(LinkNum) (LmSCRATCH(LinkNum) + 0x00A0) | ||
2237 | #define LmSEQ_M1_SG_LIST_PTR_ADDR1(LinkNum) (LmSCRATCH(LinkNum) + 0x00B0) | ||
2238 | |||
2239 | /* Mode dependent scratch page 1 macros for mode 2 */ | ||
2240 | /* Absolute offsets */ | ||
2241 | #define LmSEQ_INVALID_DWORD_COUNT(LinkNum) (LmSCRATCH(LinkNum) + 0x0120) | ||
2242 | #define LmSEQ_DISPARITY_ERROR_COUNT(LinkNum) (LmSCRATCH(LinkNum) + 0x0124) | ||
2243 | #define LmSEQ_LOSS_OF_SYNC_COUNT(LinkNum) (LmSCRATCH(LinkNum) + 0x0128) | ||
2244 | |||
2245 | /* Mode dependent scratch page 1 macros for mode 4/5 */ | ||
2246 | #define LmSEQ_FRAME_TYPE_MASK(LinkNum) (LmSCRATCH(LinkNum) + 0x00E0) | ||
2247 | #define LmSEQ_HASHED_DEST_ADDR_MASK(LinkNum) (LmSCRATCH(LinkNum) + 0x00E1) | ||
2248 | #define LmSEQ_HASHED_SRC_ADDR_MASK_PRINT(LinkNum) (LmSCRATCH(LinkNum) + 0x00E4) | ||
2249 | #define LmSEQ_HASHED_SRC_ADDR_MASK(LinkNum) (LmSCRATCH(LinkNum) + 0x00E5) | ||
2250 | #define LmSEQ_NUM_FILL_BYTES_MASK(LinkNum) (LmSCRATCH(LinkNum) + 0x00EB) | ||
2251 | #define LmSEQ_TAG_MASK(LinkNum) (LmSCRATCH(LinkNum) + 0x00F0) | ||
2252 | #define LmSEQ_TARGET_PORT_XFER_TAG(LinkNum) (LmSCRATCH(LinkNum) + 0x00F2) | ||
2253 | #define LmSEQ_DATA_OFFSET(LinkNum) (LmSCRATCH(LinkNum) + 0x00F4) | ||
2254 | |||
2255 | /* Mode dependent scratch page 2 macros for mode 0 */ | ||
2256 | /* Absolute offsets */ | ||
2257 | #define LmSEQ_SMP_RCV_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x0040) | ||
2258 | #define LmSEQ_DEVICE_BITS(LinkNum) (LmSCRATCH(LinkNum) + 0x005B) | ||
2259 | #define LmSEQ_SDB_DDB(LinkNum) (LmSCRATCH(LinkNum) + 0x005C) | ||
2260 | #define LmSEQ_SDB_NUM_TAGS(LinkNum) (LmSCRATCH(LinkNum) + 0x005E) | ||
2261 | #define LmSEQ_SDB_CURR_TAG(LinkNum) (LmSCRATCH(LinkNum) + 0x005F) | ||
2262 | |||
2263 | /* Mode dependent scratch page 2 macros for mode 1 */ | ||
2264 | /* Absolute offsets */ | ||
2265 | /* byte 0 bits 1-0 are domain select. */ | ||
2266 | #define LmSEQ_TX_ID_ADDR_FRAME(LinkNum) (LmSCRATCH(LinkNum) + 0x00C0) | ||
2267 | #define LmSEQ_OPEN_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x00C8) | ||
2268 | #define LmSEQ_SRST_AS_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x00CC) | ||
2269 | #define LmSEQ_LAST_LOADED_SG_EL(LinkNum) (LmSCRATCH(LinkNum) + 0x00D4) | ||
2270 | |||
2271 | /* Mode dependent scratch page 2 macros for mode 2 */ | ||
2272 | /* Absolute offsets */ | ||
2273 | #define LmSEQ_STP_SHUTDOWN_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x0140) | ||
2274 | #define LmSEQ_CLOSE_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x0144) | ||
2275 | #define LmSEQ_BREAK_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x0148) | ||
2276 | #define LmSEQ_DWS_RESET_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x014C) | ||
2277 | #define LmSEQ_SATA_INTERLOCK_TIMER_TERM_TS(LinkNum) \ | ||
2278 | (LmSCRATCH(LinkNum) + 0x0150) | ||
2279 | #define LmSEQ_MCTL_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x0154) | ||
2280 | |||
2281 | /* Mode dependent scratch page 2 macros for mode 5 */ | ||
2282 | #define LmSEQ_COMINIT_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x0160) | ||
2283 | #define LmSEQ_RCV_ID_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x0164) | ||
2284 | #define LmSEQ_RCV_FIS_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x0168) | ||
2285 | #define LmSEQ_DEV_PRES_TIMER_TERM_TS(LinkNum) (LmSCRATCH(LinkNum) + 0x016C) | ||
2286 | |||
2287 | /* Mode dependent scratch page 3 macros for modes 0 and 1 */ | ||
2288 | /* None defined */ | ||
2289 | |||
2290 | /* Mode dependent scratch page 3 macros for modes 2 and 5 */ | ||
2291 | /* None defined */ | ||
2292 | |||
2293 | /* Mode Independent Scratch page 0 macros. */ | ||
2294 | #define LmSEQ_Q_TGTXFR_HEAD(LinkNum) (LmSCRATCH(LinkNum) + 0x0180) | ||
2295 | #define LmSEQ_Q_TGTXFR_TAIL(LinkNum) (LmSCRATCH(LinkNum) + 0x0182) | ||
2296 | #define LmSEQ_LINK_NUMBER(LinkNum) (LmSCRATCH(LinkNum) + 0x0186) | ||
2297 | #define LmSEQ_SCRATCH_FLAGS(LinkNum) (LmSCRATCH(LinkNum) + 0x0187) | ||
2298 | /* | ||
2299 | * Currently only bit 0, SAS_DWSAQD, is used. | ||
2300 | */ | ||
2301 | #define SAS_DWSAQD 0x01 /* | ||
2302 | * DWSSTATUS: DWSAQD | ||
2303 | * bit las read in ISR. | ||
2304 | */ | ||
2305 | #define LmSEQ_CONNECTION_STATE(LinkNum) (LmSCRATCH(LinkNum) + 0x0188) | ||
2306 | /* Connection states (byte 0) */ | ||
2307 | #define SAS_WE_OPENED_CS 0x01 | ||
2308 | #define SAS_DEVICE_OPENED_CS 0x02 | ||
2309 | #define SAS_WE_SENT_DONE_CS 0x04 | ||
2310 | #define SAS_DEVICE_SENT_DONE_CS 0x08 | ||
2311 | #define SAS_WE_SENT_CLOSE_CS 0x10 | ||
2312 | #define SAS_DEVICE_SENT_CLOSE_CS 0x20 | ||
2313 | #define SAS_WE_SENT_BREAK_CS 0x40 | ||
2314 | #define SAS_DEVICE_SENT_BREAK_CS 0x80 | ||
2315 | /* Connection states (byte 1) */ | ||
2316 | #define SAS_OPN_TIMEOUT_OR_OPN_RJCT_CS 0x01 | ||
2317 | #define SAS_AIP_RECEIVED_CS 0x02 | ||
2318 | #define SAS_CREDIT_TIMEOUT_OCCURRED_CS 0x04 | ||
2319 | #define SAS_ACKNAK_TIMEOUT_OCCURRED_CS 0x08 | ||
2320 | #define SAS_SMPRSP_TIMEOUT_OCCURRED_CS 0x10 | ||
2321 | #define SAS_DONE_TIMEOUT_OCCURRED_CS 0x20 | ||
2322 | /* Connection states (byte 2) */ | ||
2323 | #define SAS_SMP_RESPONSE_RECEIVED_CS 0x01 | ||
2324 | #define SAS_INTLK_TIMEOUT_OCCURRED_CS 0x02 | ||
2325 | #define SAS_DEVICE_SENT_DMAT_CS 0x04 | ||
2326 | #define SAS_DEVICE_SENT_SYNCSRST_CS 0x08 | ||
2327 | #define SAS_CLEARING_AFFILIATION_CS 0x20 | ||
2328 | #define SAS_RXTASK_ACTIVE_CS 0x40 | ||
2329 | #define SAS_TXTASK_ACTIVE_CS 0x80 | ||
2330 | /* Connection states (byte 3) */ | ||
2331 | #define SAS_PHY_LOSS_OF_SIGNAL_CS 0x01 | ||
2332 | #define SAS_DWS_TIMER_EXPIRED_CS 0x02 | ||
2333 | #define SAS_LINK_RESET_NOT_COMPLETE_CS 0x04 | ||
2334 | #define SAS_PHY_DISABLED_CS 0x08 | ||
2335 | #define SAS_LINK_CTL_TASK_ACTIVE_CS 0x10 | ||
2336 | #define SAS_PHY_EVENT_TASK_ACTIVE_CS 0x20 | ||
2337 | #define SAS_DEVICE_SENT_ID_FRAME_CS 0x40 | ||
2338 | #define SAS_DEVICE_SENT_REG_FIS_CS 0x40 | ||
2339 | #define SAS_DEVICE_SENT_HARD_RESET_CS 0x80 | ||
2340 | #define SAS_PHY_IS_DOWN_FLAGS (SAS_PHY_LOSS_OF_SIGNAL_CS|\ | ||
2341 | SAS_DWS_TIMER_EXPIRED_CS |\ | ||
2342 | SAS_LINK_RESET_NOT_COMPLETE_CS|\ | ||
2343 | SAS_PHY_DISABLED_CS) | ||
2344 | |||
2345 | #define SAS_LINK_CTL_PHY_EVENT_FLAGS (SAS_LINK_CTL_TASK_ACTIVE_CS |\ | ||
2346 | SAS_PHY_EVENT_TASK_ACTIVE_CS |\ | ||
2347 | SAS_DEVICE_SENT_ID_FRAME_CS |\ | ||
2348 | SAS_DEVICE_SENT_HARD_RESET_CS) | ||
2349 | |||
2350 | #define LmSEQ_CONCTL(LinkNum) (LmSCRATCH(LinkNum) + 0x018C) | ||
2351 | #define LmSEQ_CONSTAT(LinkNum) (LmSCRATCH(LinkNum) + 0x018E) | ||
2352 | #define LmSEQ_CONNECTION_MODES(LinkNum) (LmSCRATCH(LinkNum) + 0x018F) | ||
2353 | #define LmSEQ_REG1_ISR(LinkNum) (LmSCRATCH(LinkNum) + 0x0192) | ||
2354 | #define LmSEQ_REG2_ISR(LinkNum) (LmSCRATCH(LinkNum) + 0x0194) | ||
2355 | #define LmSEQ_REG3_ISR(LinkNum) (LmSCRATCH(LinkNum) + 0x0196) | ||
2356 | #define LmSEQ_REG0_ISR(LinkNum) (LmSCRATCH(LinkNum) + 0x0198) | ||
2357 | |||
2358 | /* Mode independent scratch page 1 macros. */ | ||
2359 | #define LmSEQ_EST_NEXUS_SCBPTR0(LinkNum) (LmSCRATCH(LinkNum) + 0x01A0) | ||
2360 | #define LmSEQ_EST_NEXUS_SCBPTR1(LinkNum) (LmSCRATCH(LinkNum) + 0x01A2) | ||
2361 | #define LmSEQ_EST_NEXUS_SCBPTR2(LinkNum) (LmSCRATCH(LinkNum) + 0x01A4) | ||
2362 | #define LmSEQ_EST_NEXUS_SCBPTR3(LinkNum) (LmSCRATCH(LinkNum) + 0x01A6) | ||
2363 | #define LmSEQ_EST_NEXUS_SCB_OPCODE0(LinkNum) (LmSCRATCH(LinkNum) + 0x01A8) | ||
2364 | #define LmSEQ_EST_NEXUS_SCB_OPCODE1(LinkNum) (LmSCRATCH(LinkNum) + 0x01A9) | ||
2365 | #define LmSEQ_EST_NEXUS_SCB_OPCODE2(LinkNum) (LmSCRATCH(LinkNum) + 0x01AA) | ||
2366 | #define LmSEQ_EST_NEXUS_SCB_OPCODE3(LinkNum) (LmSCRATCH(LinkNum) + 0x01AB) | ||
2367 | #define LmSEQ_EST_NEXUS_SCB_HEAD(LinkNum) (LmSCRATCH(LinkNum) + 0x01AC) | ||
2368 | #define LmSEQ_EST_NEXUS_SCB_TAIL(LinkNum) (LmSCRATCH(LinkNum) + 0x01AD) | ||
2369 | #define LmSEQ_EST_NEXUS_BUF_AVAIL(LinkNum) (LmSCRATCH(LinkNum) + 0x01AE) | ||
2370 | #define LmSEQ_TIMEOUT_CONST(LinkNum) (LmSCRATCH(LinkNum) + 0x01B8) | ||
2371 | #define LmSEQ_ISR_SAVE_SINDEX(LinkNum) (LmSCRATCH(LinkNum) + 0x01BC) | ||
2372 | #define LmSEQ_ISR_SAVE_DINDEX(LinkNum) (LmSCRATCH(LinkNum) + 0x01BE) | ||
2373 | |||
2374 | /* Mode independent scratch page 2 macros. */ | ||
2375 | #define LmSEQ_EMPTY_SCB_PTR0(LinkNum) (LmSCRATCH(LinkNum) + 0x01C0) | ||
2376 | #define LmSEQ_EMPTY_SCB_PTR1(LinkNum) (LmSCRATCH(LinkNum) + 0x01C2) | ||
2377 | #define LmSEQ_EMPTY_SCB_PTR2(LinkNum) (LmSCRATCH(LinkNum) + 0x01C4) | ||
2378 | #define LmSEQ_EMPTY_SCB_PTR3(LinkNum) (LmSCRATCH(LinkNum) + 0x01C6) | ||
2379 | #define LmSEQ_EMPTY_SCB_OPCD0(LinkNum) (LmSCRATCH(LinkNum) + 0x01C8) | ||
2380 | #define LmSEQ_EMPTY_SCB_OPCD1(LinkNum) (LmSCRATCH(LinkNum) + 0x01C9) | ||
2381 | #define LmSEQ_EMPTY_SCB_OPCD2(LinkNum) (LmSCRATCH(LinkNum) + 0x01CA) | ||
2382 | #define LmSEQ_EMPTY_SCB_OPCD3(LinkNum) (LmSCRATCH(LinkNum) + 0x01CB) | ||
2383 | #define LmSEQ_EMPTY_SCB_HEAD(LinkNum) (LmSCRATCH(LinkNum) + 0x01CC) | ||
2384 | #define LmSEQ_EMPTY_SCB_TAIL(LinkNum) (LmSCRATCH(LinkNum) + 0x01CD) | ||
2385 | #define LmSEQ_EMPTY_BUFS_AVAIL(LinkNum) (LmSCRATCH(LinkNum) + 0x01CE) | ||
2386 | #define LmSEQ_ATA_SCR_REGS(LinkNum) (LmSCRATCH(LinkNum) + 0x01D4) | ||
2387 | |||
2388 | /* Mode independent scratch page 3 macros. */ | ||
2389 | #define LmSEQ_DEV_PRES_TMR_TOUT_CONST(LinkNum) (LmSCRATCH(LinkNum) + 0x01E0) | ||
2390 | #define LmSEQ_SATA_INTERLOCK_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x01E4) | ||
2391 | #define LmSEQ_STP_SHUTDOWN_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x01E8) | ||
2392 | #define LmSEQ_SRST_ASSERT_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x01EC) | ||
2393 | #define LmSEQ_RCV_FIS_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x01F0) | ||
2394 | #define LmSEQ_ONE_MILLISEC_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x01F4) | ||
2395 | #define LmSEQ_TEN_MS_COMINIT_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x01F8) | ||
2396 | #define LmSEQ_SMP_RCV_TIMEOUT(LinkNum) (LmSCRATCH(LinkNum) + 0x01FC) | ||
2397 | |||
2398 | #endif | ||
diff --git a/drivers/scsi/aic94xx/aic94xx_sas.h b/drivers/scsi/aic94xx/aic94xx_sas.h new file mode 100644 index 000000000000..64d231712345 --- /dev/null +++ b/drivers/scsi/aic94xx/aic94xx_sas.h | |||
@@ -0,0 +1,785 @@ | |||
1 | /* | ||
2 | * Aic94xx SAS/SATA driver SAS definitions and hardware interface header file. | ||
3 | * | ||
4 | * Copyright (C) 2005 Adaptec, Inc. All rights reserved. | ||
5 | * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> | ||
6 | * | ||
7 | * This file is licensed under GPLv2. | ||
8 | * | ||
9 | * This file is part of the aic94xx driver. | ||
10 | * | ||
11 | * The aic94xx driver is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License as | ||
13 | * published by the Free Software Foundation; version 2 of the | ||
14 | * License. | ||
15 | * | ||
16 | * The aic94xx driver is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
19 | * General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with the aic94xx driver; if not, write to the Free Software | ||
23 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #ifndef _AIC94XX_SAS_H_ | ||
28 | #define _AIC94XX_SAS_H_ | ||
29 | |||
30 | #include <scsi/libsas.h> | ||
31 | |||
32 | /* ---------- DDBs ---------- */ | ||
33 | /* DDBs are device descriptor blocks which describe a device in the | ||
34 | * domain that this sequencer can maintain low-level connections for | ||
35 | * us. They are be 64 bytes. | ||
36 | */ | ||
37 | |||
38 | struct asd_ddb_ssp_smp_target_port { | ||
39 | u8 conn_type; /* byte 0 */ | ||
40 | #define DDB_TP_CONN_TYPE 0x81 /* Initiator port and addr frame type 0x01 */ | ||
41 | |||
42 | u8 conn_rate; | ||
43 | __be16 init_conn_tag; | ||
44 | u8 dest_sas_addr[8]; /* bytes 4-11 */ | ||
45 | |||
46 | __le16 send_queue_head; | ||
47 | u8 sq_suspended; | ||
48 | u8 ddb_type; /* DDB_TYPE_TARGET */ | ||
49 | #define DDB_TYPE_UNUSED 0xFF | ||
50 | #define DDB_TYPE_TARGET 0xFE | ||
51 | #define DDB_TYPE_INITIATOR 0xFD | ||
52 | #define DDB_TYPE_PM_PORT 0xFC | ||
53 | |||
54 | __le16 _r_a; | ||
55 | __be16 awt_def; | ||
56 | |||
57 | u8 compat_features; /* byte 20 */ | ||
58 | u8 pathway_blocked_count; | ||
59 | __be16 arb_wait_time; | ||
60 | __be32 more_compat_features; /* byte 24 */ | ||
61 | |||
62 | u8 conn_mask; | ||
63 | u8 flags; /* concurrent conn:2,2 and open:0(1) */ | ||
64 | #define CONCURRENT_CONN_SUPP 0x04 | ||
65 | #define OPEN_REQUIRED 0x01 | ||
66 | |||
67 | u16 _r_b; | ||
68 | __le16 exec_queue_tail; | ||
69 | __le16 send_queue_tail; | ||
70 | __le16 sister_ddb; | ||
71 | |||
72 | __le16 _r_c; | ||
73 | |||
74 | u8 max_concurrent_conn; | ||
75 | u8 num_concurrent_conn; | ||
76 | u8 num_contexts; | ||
77 | |||
78 | u8 _r_d; | ||
79 | |||
80 | __le16 active_task_count; | ||
81 | |||
82 | u8 _r_e[9]; | ||
83 | |||
84 | u8 itnl_reason; /* I_T nexus loss reason */ | ||
85 | |||
86 | __le16 _r_f; | ||
87 | |||
88 | __le16 itnl_timeout; | ||
89 | #define ITNL_TIMEOUT_CONST 0x7D0 /* 2 seconds */ | ||
90 | |||
91 | __le32 itnl_timestamp; | ||
92 | } __attribute__ ((packed)); | ||
93 | |||
94 | struct asd_ddb_stp_sata_target_port { | ||
95 | u8 conn_type; /* byte 0 */ | ||
96 | u8 conn_rate; | ||
97 | __be16 init_conn_tag; | ||
98 | u8 dest_sas_addr[8]; /* bytes 4-11 */ | ||
99 | |||
100 | __le16 send_queue_head; | ||
101 | u8 sq_suspended; | ||
102 | u8 ddb_type; /* DDB_TYPE_TARGET */ | ||
103 | |||
104 | __le16 _r_a; | ||
105 | |||
106 | __be16 awt_def; | ||
107 | u8 compat_features; /* byte 20 */ | ||
108 | u8 pathway_blocked_count; | ||
109 | __be16 arb_wait_time; | ||
110 | __be32 more_compat_features; /* byte 24 */ | ||
111 | |||
112 | u8 conn_mask; | ||
113 | u8 flags; /* concurrent conn:2,2 and open:0(1) */ | ||
114 | #define SATA_MULTIPORT 0x80 | ||
115 | #define SUPPORTS_AFFIL 0x40 | ||
116 | #define STP_AFFIL_POL 0x20 | ||
117 | |||
118 | u8 _r_b; | ||
119 | u8 flags2; /* STP close policy:0 */ | ||
120 | #define STP_CL_POL_NO_TX 0x00 | ||
121 | #define STP_CL_POL_BTW_CMDS 0x01 | ||
122 | |||
123 | __le16 exec_queue_tail; | ||
124 | __le16 send_queue_tail; | ||
125 | __le16 sister_ddb; | ||
126 | __le16 ata_cmd_scbptr; | ||
127 | __le32 sata_tag_alloc_mask; | ||
128 | __le16 active_task_count; | ||
129 | __le16 _r_c; | ||
130 | __le32 sata_sactive; | ||
131 | u8 num_sata_tags; | ||
132 | u8 sata_status; | ||
133 | u8 sata_ending_status; | ||
134 | u8 itnl_reason; /* I_T nexus loss reason */ | ||
135 | __le16 ncq_data_scb_ptr; | ||
136 | __le16 itnl_timeout; | ||
137 | __le32 itnl_timestamp; | ||
138 | } __attribute__ ((packed)); | ||
139 | |||
140 | /* This struct asd_ddb_init_port, describes the device descriptor block | ||
141 | * of an initiator port (when the sequencer is operating in target mode). | ||
142 | * Bytes [0,11] and [20,27] are from the OPEN address frame. | ||
143 | * The sequencer allocates an initiator port DDB entry. | ||
144 | */ | ||
145 | struct asd_ddb_init_port { | ||
146 | u8 conn_type; /* byte 0 */ | ||
147 | u8 conn_rate; | ||
148 | __be16 init_conn_tag; /* BE */ | ||
149 | u8 dest_sas_addr[8]; | ||
150 | __le16 send_queue_head; /* LE, byte 12 */ | ||
151 | u8 sq_suspended; | ||
152 | u8 ddb_type; /* DDB_TYPE_INITIATOR */ | ||
153 | __le16 _r_a; | ||
154 | __be16 awt_def; /* BE */ | ||
155 | u8 compat_features; | ||
156 | u8 pathway_blocked_count; | ||
157 | __be16 arb_wait_time; /* BE */ | ||
158 | __be32 more_compat_features; /* BE */ | ||
159 | u8 conn_mask; | ||
160 | u8 flags; /* == 5 */ | ||
161 | u16 _r_b; | ||
162 | __le16 exec_queue_tail; /* execution queue tail */ | ||
163 | __le16 send_queue_tail; | ||
164 | __le16 sister_ddb; | ||
165 | __le16 init_resp_timeout; /* initiator response timeout */ | ||
166 | __le32 _r_c; | ||
167 | __le16 active_tasks; /* active task count */ | ||
168 | __le16 init_list; /* initiator list link pointer */ | ||
169 | __le32 _r_d; | ||
170 | u8 max_conn_to[3]; /* from Conn-Disc mode page, in us, LE */ | ||
171 | u8 itnl_reason; /* I_T nexus loss reason */ | ||
172 | __le16 bus_inact_to; /* from Conn-Disc mode page, in 100 us, LE */ | ||
173 | __le16 itnl_to; /* from the Protocol Specific Port Ctrl MP */ | ||
174 | __le32 itnl_timestamp; | ||
175 | } __attribute__ ((packed)); | ||
176 | |||
177 | /* This struct asd_ddb_sata_tag, describes a look-up table to be used | ||
178 | * by the sequencers. SATA II, IDENTIFY DEVICE data, word 76, bit 8: | ||
179 | * NCQ support. This table is used by the sequencers to find the | ||
180 | * corresponding SCB, given a SATA II tag value. | ||
181 | */ | ||
182 | struct asd_ddb_sata_tag { | ||
183 | __le16 scb_pointer[32]; | ||
184 | } __attribute__ ((packed)); | ||
185 | |||
186 | /* This struct asd_ddb_sata_pm_table, describes a port number to | ||
187 | * connection handle look-up table. SATA targets attached to a port | ||
188 | * multiplier require a 4-bit port number value. There is one DDB | ||
189 | * entry of this type for each SATA port multiplier (sister DDB). | ||
190 | * Given a SATA PM port number, this table gives us the SATA PM Port | ||
191 | * DDB of the SATA port multiplier port (i.e. the SATA target | ||
192 | * discovered on the port). | ||
193 | */ | ||
194 | struct asd_ddb_sata_pm_table { | ||
195 | __le16 ddb_pointer[16]; | ||
196 | __le16 _r_a[16]; | ||
197 | } __attribute__ ((packed)); | ||
198 | |||
199 | /* This struct asd_ddb_sata_pm_port, describes the SATA port multiplier | ||
200 | * port format DDB. | ||
201 | */ | ||
202 | struct asd_ddb_sata_pm_port { | ||
203 | u8 _r_a[15]; | ||
204 | u8 ddb_type; | ||
205 | u8 _r_b[13]; | ||
206 | u8 pm_port_flags; | ||
207 | #define PM_PORT_MASK 0xF0 | ||
208 | #define PM_PORT_SET 0x02 | ||
209 | u8 _r_c[6]; | ||
210 | __le16 sister_ddb; | ||
211 | __le16 ata_cmd_scbptr; | ||
212 | __le32 sata_tag_alloc_mask; | ||
213 | __le16 active_task_count; | ||
214 | __le16 parent_ddb; | ||
215 | __le32 sata_sactive; | ||
216 | u8 num_sata_tags; | ||
217 | u8 sata_status; | ||
218 | u8 sata_ending_status; | ||
219 | u8 _r_d[9]; | ||
220 | } __attribute__ ((packed)); | ||
221 | |||
222 | /* This struct asd_ddb_seq_shared, describes a DDB shared by the | ||
223 | * central and link sequencers. port_map_by_links is indexed phy | ||
224 | * number [0,7]; each byte is a bit mask of all the phys that are in | ||
225 | * the same port as the indexed phy. | ||
226 | */ | ||
227 | struct asd_ddb_seq_shared { | ||
228 | __le16 q_free_ddb_head; | ||
229 | __le16 q_free_ddb_tail; | ||
230 | __le16 q_free_ddb_cnt; | ||
231 | __le16 q_used_ddb_head; | ||
232 | __le16 q_used_ddb_tail; | ||
233 | __le16 shared_mem_lock; | ||
234 | __le16 smp_conn_tag; | ||
235 | __le16 est_nexus_buf_cnt; | ||
236 | __le16 est_nexus_buf_thresh; | ||
237 | u32 _r_a; | ||
238 | u8 settable_max_contexts; | ||
239 | u8 _r_b[23]; | ||
240 | u8 conn_not_active; | ||
241 | u8 phy_is_up; | ||
242 | u8 _r_c[8]; | ||
243 | u8 port_map_by_links[8]; | ||
244 | } __attribute__ ((packed)); | ||
245 | |||
246 | /* ---------- SG Element ---------- */ | ||
247 | |||
248 | /* This struct sg_el, describes the hardware scatter gather buffer | ||
249 | * element. All entries are little endian. In an SCB, there are 2 of | ||
250 | * this, plus one more, called a link element of this indicating a | ||
251 | * sublist if needed. | ||
252 | * | ||
253 | * A link element has only the bus address set and the flags (DS) bit | ||
254 | * valid. The bus address points to the start of the sublist. | ||
255 | * | ||
256 | * If a sublist is needed, then that sublist should also include the 2 | ||
257 | * sg_el embedded in the SCB, in which case next_sg_offset is 32, | ||
258 | * since sizeof(sg_el) = 16; EOS should be 1 and EOL 0 in this case. | ||
259 | */ | ||
260 | struct sg_el { | ||
261 | __le64 bus_addr; | ||
262 | __le32 size; | ||
263 | __le16 _r; | ||
264 | u8 next_sg_offs; | ||
265 | u8 flags; | ||
266 | #define ASD_SG_EL_DS_MASK 0x30 | ||
267 | #define ASD_SG_EL_DS_OCM 0x10 | ||
268 | #define ASD_SG_EL_DS_HM 0x00 | ||
269 | #define ASD_SG_EL_LIST_MASK 0xC0 | ||
270 | #define ASD_SG_EL_LIST_EOL 0x40 | ||
271 | #define ASD_SG_EL_LIST_EOS 0x80 | ||
272 | } __attribute__ ((packed)); | ||
273 | |||
274 | /* ---------- SCBs ---------- */ | ||
275 | |||
276 | /* An SCB (sequencer control block) is comprised of a common header | ||
277 | * and a task part, for a total of 128 bytes. All fields are in LE | ||
278 | * order, unless otherwise noted. | ||
279 | */ | ||
280 | |||
281 | /* This struct scb_header, defines the SCB header format. | ||
282 | */ | ||
283 | struct scb_header { | ||
284 | __le64 next_scb; | ||
285 | __le16 index; /* transaction context */ | ||
286 | u8 opcode; | ||
287 | } __attribute__ ((packed)); | ||
288 | |||
289 | /* SCB opcodes: Execution queue | ||
290 | */ | ||
291 | #define INITIATE_SSP_TASK 0x00 | ||
292 | #define INITIATE_LONG_SSP_TASK 0x01 | ||
293 | #define INITIATE_BIDIR_SSP_TASK 0x02 | ||
294 | #define ABORT_TASK 0x03 | ||
295 | #define INITIATE_SSP_TMF 0x04 | ||
296 | #define SSP_TARG_GET_DATA 0x05 | ||
297 | #define SSP_TARG_GET_DATA_GOOD 0x06 | ||
298 | #define SSP_TARG_SEND_RESP 0x07 | ||
299 | #define QUERY_SSP_TASK 0x08 | ||
300 | #define INITIATE_ATA_TASK 0x09 | ||
301 | #define INITIATE_ATAPI_TASK 0x0a | ||
302 | #define CONTROL_ATA_DEV 0x0b | ||
303 | #define INITIATE_SMP_TASK 0x0c | ||
304 | #define SMP_TARG_SEND_RESP 0x0f | ||
305 | |||
306 | /* SCB opcodes: Send Queue | ||
307 | */ | ||
308 | #define SSP_TARG_SEND_DATA 0x40 | ||
309 | #define SSP_TARG_SEND_DATA_GOOD 0x41 | ||
310 | |||
311 | /* SCB opcodes: Link Queue | ||
312 | */ | ||
313 | #define CONTROL_PHY 0x80 | ||
314 | #define SEND_PRIMITIVE 0x81 | ||
315 | #define INITIATE_LINK_ADM_TASK 0x82 | ||
316 | |||
317 | /* SCB opcodes: other | ||
318 | */ | ||
319 | #define EMPTY_SCB 0xc0 | ||
320 | #define INITIATE_SEQ_ADM_TASK 0xc1 | ||
321 | #define EST_ICL_TARG_WINDOW 0xc2 | ||
322 | #define COPY_MEM 0xc3 | ||
323 | #define CLEAR_NEXUS 0xc4 | ||
324 | #define INITIATE_DDB_ADM_TASK 0xc6 | ||
325 | #define ESTABLISH_NEXUS_ESCB 0xd0 | ||
326 | |||
327 | #define LUN_SIZE 8 | ||
328 | |||
329 | /* See SAS spec, task IU | ||
330 | */ | ||
331 | struct ssp_task_iu { | ||
332 | u8 lun[LUN_SIZE]; /* BE */ | ||
333 | u16 _r_a; | ||
334 | u8 tmf; | ||
335 | u8 _r_b; | ||
336 | __be16 tag; /* BE */ | ||
337 | u8 _r_c[14]; | ||
338 | } __attribute__ ((packed)); | ||
339 | |||
340 | /* See SAS spec, command IU | ||
341 | */ | ||
342 | struct ssp_command_iu { | ||
343 | u8 lun[LUN_SIZE]; | ||
344 | u8 _r_a; | ||
345 | u8 efb_prio_attr; /* enable first burst, task prio & attr */ | ||
346 | #define EFB_MASK 0x80 | ||
347 | #define TASK_PRIO_MASK 0x78 | ||
348 | #define TASK_ATTR_MASK 0x07 | ||
349 | |||
350 | u8 _r_b; | ||
351 | u8 add_cdb_len; /* in dwords, since bit 0,1 are reserved */ | ||
352 | union { | ||
353 | u8 cdb[16]; | ||
354 | struct { | ||
355 | __le64 long_cdb_addr; /* bus address, LE */ | ||
356 | __le32 long_cdb_size; /* LE */ | ||
357 | u8 _r_c[3]; | ||
358 | u8 eol_ds; /* eol:6,6, ds:5,4 */ | ||
359 | } long_cdb; /* sequencer extension */ | ||
360 | }; | ||
361 | } __attribute__ ((packed)); | ||
362 | |||
363 | struct xfer_rdy_iu { | ||
364 | __be32 requested_offset; /* BE */ | ||
365 | __be32 write_data_len; /* BE */ | ||
366 | __be32 _r_a; | ||
367 | } __attribute__ ((packed)); | ||
368 | |||
369 | /* ---------- SCB tasks ---------- */ | ||
370 | |||
371 | /* This is both ssp_task and long_ssp_task | ||
372 | */ | ||
373 | struct initiate_ssp_task { | ||
374 | u8 proto_conn_rate; /* proto:6,4, conn_rate:3,0 */ | ||
375 | __le32 total_xfer_len; | ||
376 | struct ssp_frame_hdr ssp_frame; | ||
377 | struct ssp_command_iu ssp_cmd; | ||
378 | __le16 sister_scb; /* 0xFFFF */ | ||
379 | __le16 conn_handle; /* index to DDB for the intended target */ | ||
380 | u8 data_dir; /* :1,0 */ | ||
381 | #define DATA_DIR_NONE 0x00 | ||
382 | #define DATA_DIR_IN 0x01 | ||
383 | #define DATA_DIR_OUT 0x02 | ||
384 | #define DATA_DIR_BYRECIPIENT 0x03 | ||
385 | |||
386 | u8 _r_a; | ||
387 | u8 retry_count; | ||
388 | u8 _r_b[5]; | ||
389 | struct sg_el sg_element[3]; /* 2 real and 1 link */ | ||
390 | } __attribute__ ((packed)); | ||
391 | |||
392 | /* This defines both ata_task and atapi_task. | ||
393 | * ata: C bit of FIS should be 1, | ||
394 | * atapi: C bit of FIS should be 1, and command register should be 0xA0, | ||
395 | * to indicate a packet command. | ||
396 | */ | ||
397 | struct initiate_ata_task { | ||
398 | u8 proto_conn_rate; | ||
399 | __le32 total_xfer_len; | ||
400 | struct host_to_dev_fis fis; | ||
401 | __le32 data_offs; | ||
402 | u8 atapi_packet[16]; | ||
403 | u8 _r_a[12]; | ||
404 | __le16 sister_scb; | ||
405 | __le16 conn_handle; | ||
406 | u8 ata_flags; /* CSMI:6,6, DTM:4,4, QT:3,3, data dir:1,0 */ | ||
407 | #define CSMI_TASK 0x40 | ||
408 | #define DATA_XFER_MODE_DMA 0x10 | ||
409 | #define ATA_Q_TYPE_MASK 0x08 | ||
410 | #define ATA_Q_TYPE_UNTAGGED 0x00 | ||
411 | #define ATA_Q_TYPE_NCQ 0x08 | ||
412 | |||
413 | u8 _r_b; | ||
414 | u8 retry_count; | ||
415 | u8 _r_c; | ||
416 | u8 flags; | ||
417 | #define STP_AFFIL_POLICY 0x20 | ||
418 | #define SET_AFFIL_POLICY 0x10 | ||
419 | #define RET_PARTIAL_SGLIST 0x02 | ||
420 | |||
421 | u8 _r_d[3]; | ||
422 | struct sg_el sg_element[3]; | ||
423 | } __attribute__ ((packed)); | ||
424 | |||
425 | struct initiate_smp_task { | ||
426 | u8 proto_conn_rate; | ||
427 | u8 _r_a[40]; | ||
428 | struct sg_el smp_req; | ||
429 | __le16 sister_scb; | ||
430 | __le16 conn_handle; | ||
431 | u8 _r_c[8]; | ||
432 | struct sg_el smp_resp; | ||
433 | u8 _r_d[32]; | ||
434 | } __attribute__ ((packed)); | ||
435 | |||
436 | struct control_phy { | ||
437 | u8 phy_id; | ||
438 | u8 sub_func; | ||
439 | #define DISABLE_PHY 0x00 | ||
440 | #define ENABLE_PHY 0x01 | ||
441 | #define RELEASE_SPINUP_HOLD 0x02 | ||
442 | #define ENABLE_PHY_NO_SAS_OOB 0x03 | ||
443 | #define ENABLE_PHY_NO_SATA_OOB 0x04 | ||
444 | #define PHY_NO_OP 0x05 | ||
445 | #define EXECUTE_HARD_RESET 0x81 | ||
446 | |||
447 | u8 func_mask; | ||
448 | u8 speed_mask; | ||
449 | u8 hot_plug_delay; | ||
450 | u8 port_type; | ||
451 | u8 flags; | ||
452 | #define DEV_PRES_TIMER_OVERRIDE_ENABLE 0x01 | ||
453 | #define DISABLE_PHY_IF_OOB_FAILS 0x02 | ||
454 | |||
455 | __le32 timeout_override; | ||
456 | u8 link_reset_retries; | ||
457 | u8 _r_a[47]; | ||
458 | __le16 conn_handle; | ||
459 | u8 _r_b[56]; | ||
460 | } __attribute__ ((packed)); | ||
461 | |||
462 | struct control_ata_dev { | ||
463 | u8 proto_conn_rate; | ||
464 | __le32 _r_a; | ||
465 | struct host_to_dev_fis fis; | ||
466 | u8 _r_b[32]; | ||
467 | __le16 sister_scb; | ||
468 | __le16 conn_handle; | ||
469 | u8 ata_flags; /* 0 */ | ||
470 | u8 _r_c[55]; | ||
471 | } __attribute__ ((packed)); | ||
472 | |||
473 | struct empty_scb { | ||
474 | u8 num_valid; | ||
475 | __le32 _r_a; | ||
476 | #define ASD_EDBS_PER_SCB 7 | ||
477 | /* header+data+CRC+DMA suffix data */ | ||
478 | #define ASD_EDB_SIZE (24+1024+4+16) | ||
479 | struct sg_el eb[ASD_EDBS_PER_SCB]; | ||
480 | #define ELEMENT_NOT_VALID 0xC0 | ||
481 | } __attribute__ ((packed)); | ||
482 | |||
483 | struct initiate_link_adm { | ||
484 | u8 phy_id; | ||
485 | u8 sub_func; | ||
486 | #define GET_LINK_ERROR_COUNT 0x00 | ||
487 | #define RESET_LINK_ERROR_COUNT 0x01 | ||
488 | #define ENABLE_NOTIFY_SPINUP_INTS 0x02 | ||
489 | |||
490 | u8 _r_a[57]; | ||
491 | __le16 conn_handle; | ||
492 | u8 _r_b[56]; | ||
493 | } __attribute__ ((packed)); | ||
494 | |||
495 | struct copy_memory { | ||
496 | u8 _r_a; | ||
497 | __le16 xfer_len; | ||
498 | __le16 _r_b; | ||
499 | __le64 src_busaddr; | ||
500 | u8 src_ds; /* See definition of sg_el */ | ||
501 | u8 _r_c[45]; | ||
502 | __le16 conn_handle; | ||
503 | __le64 _r_d; | ||
504 | __le64 dest_busaddr; | ||
505 | u8 dest_ds; /* See definition of sg_el */ | ||
506 | u8 _r_e[39]; | ||
507 | } __attribute__ ((packed)); | ||
508 | |||
509 | struct abort_task { | ||
510 | u8 proto_conn_rate; | ||
511 | __le32 _r_a; | ||
512 | struct ssp_frame_hdr ssp_frame; | ||
513 | struct ssp_task_iu ssp_task; | ||
514 | __le16 sister_scb; | ||
515 | __le16 conn_handle; | ||
516 | u8 flags; /* ovrd_itnl_timer:3,3, suspend_data_trans:2,2 */ | ||
517 | #define SUSPEND_DATA_TRANS 0x04 | ||
518 | |||
519 | u8 _r_b; | ||
520 | u8 retry_count; | ||
521 | u8 _r_c[5]; | ||
522 | __le16 index; /* Transaction context of task to be queried */ | ||
523 | __le16 itnl_to; | ||
524 | u8 _r_d[44]; | ||
525 | } __attribute__ ((packed)); | ||
526 | |||
527 | struct clear_nexus { | ||
528 | u8 nexus; | ||
529 | #define NEXUS_ADAPTER 0x00 | ||
530 | #define NEXUS_PORT 0x01 | ||
531 | #define NEXUS_I_T 0x02 | ||
532 | #define NEXUS_I_T_L 0x03 | ||
533 | #define NEXUS_TAG 0x04 | ||
534 | #define NEXUS_TRANS_CX 0x05 | ||
535 | #define NEXUS_SATA_TAG 0x06 | ||
536 | #define NEXUS_T_L 0x07 | ||
537 | #define NEXUS_L 0x08 | ||
538 | #define NEXUS_T_TAG 0x09 | ||
539 | |||
540 | __le32 _r_a; | ||
541 | u8 flags; | ||
542 | #define SUSPEND_TX 0x80 | ||
543 | #define RESUME_TX 0x40 | ||
544 | #define SEND_Q 0x04 | ||
545 | #define EXEC_Q 0x02 | ||
546 | #define NOTINQ 0x01 | ||
547 | |||
548 | u8 _r_b[3]; | ||
549 | u8 conn_mask; | ||
550 | u8 _r_c[19]; | ||
551 | struct ssp_task_iu ssp_task; /* LUN and TAG */ | ||
552 | __le16 _r_d; | ||
553 | __le16 conn_handle; | ||
554 | __le64 _r_e; | ||
555 | __le16 index; /* Transaction context of task to be cleared */ | ||
556 | __le16 context; /* Clear nexus context */ | ||
557 | u8 _r_f[44]; | ||
558 | } __attribute__ ((packed)); | ||
559 | |||
560 | struct initiate_ssp_tmf { | ||
561 | u8 proto_conn_rate; | ||
562 | __le32 _r_a; | ||
563 | struct ssp_frame_hdr ssp_frame; | ||
564 | struct ssp_task_iu ssp_task; | ||
565 | __le16 sister_scb; | ||
566 | __le16 conn_handle; | ||
567 | u8 flags; /* itnl override and suspend data tx */ | ||
568 | #define OVERRIDE_ITNL_TIMER 8 | ||
569 | |||
570 | u8 _r_b; | ||
571 | u8 retry_count; | ||
572 | u8 _r_c[5]; | ||
573 | __le16 index; /* Transaction context of task to be queried */ | ||
574 | __le16 itnl_to; | ||
575 | u8 _r_d[44]; | ||
576 | } __attribute__ ((packed)); | ||
577 | |||
578 | /* Transmits an arbitrary primitive on the link. | ||
579 | * Used for NOTIFY and BROADCAST. | ||
580 | */ | ||
581 | struct send_prim { | ||
582 | u8 phy_id; | ||
583 | u8 wait_transmit; /* :0,0 */ | ||
584 | u8 xmit_flags; | ||
585 | #define XMTPSIZE_MASK 0xF0 | ||
586 | #define XMTPSIZE_SINGLE 0x10 | ||
587 | #define XMTPSIZE_REPEATED 0x20 | ||
588 | #define XMTPSIZE_CONT 0x20 | ||
589 | #define XMTPSIZE_TRIPLE 0x30 | ||
590 | #define XMTPSIZE_REDUNDANT 0x60 | ||
591 | #define XMTPSIZE_INF 0 | ||
592 | |||
593 | #define XMTCONTEN 0x04 | ||
594 | #define XMTPFRM 0x02 /* Transmit at the next frame boundary */ | ||
595 | #define XMTPIMM 0x01 /* Transmit immediately */ | ||
596 | |||
597 | __le16 _r_a; | ||
598 | u8 prim[4]; /* K, D0, D1, D2 */ | ||
599 | u8 _r_b[50]; | ||
600 | __le16 conn_handle; | ||
601 | u8 _r_c[56]; | ||
602 | } __attribute__ ((packed)); | ||
603 | |||
604 | /* This describes both SSP Target Get Data and SSP Target Get Data And | ||
605 | * Send Good Response SCBs. Used when the sequencer is operating in | ||
606 | * target mode... | ||
607 | */ | ||
608 | struct ssp_targ_get_data { | ||
609 | u8 proto_conn_rate; | ||
610 | __le32 total_xfer_len; | ||
611 | struct ssp_frame_hdr ssp_frame; | ||
612 | struct xfer_rdy_iu xfer_rdy; | ||
613 | u8 lun[LUN_SIZE]; | ||
614 | __le64 _r_a; | ||
615 | __le16 sister_scb; | ||
616 | __le16 conn_handle; | ||
617 | u8 data_dir; /* 01b */ | ||
618 | u8 _r_b; | ||
619 | u8 retry_count; | ||
620 | u8 _r_c[5]; | ||
621 | struct sg_el sg_element[3]; | ||
622 | } __attribute__ ((packed)); | ||
623 | |||
624 | /* ---------- The actual SCB struct ---------- */ | ||
625 | |||
626 | struct scb { | ||
627 | struct scb_header header; | ||
628 | union { | ||
629 | struct initiate_ssp_task ssp_task; | ||
630 | struct initiate_ata_task ata_task; | ||
631 | struct initiate_smp_task smp_task; | ||
632 | struct control_phy control_phy; | ||
633 | struct control_ata_dev control_ata_dev; | ||
634 | struct empty_scb escb; | ||
635 | struct initiate_link_adm link_adm; | ||
636 | struct copy_memory cp_mem; | ||
637 | struct abort_task abort_task; | ||
638 | struct clear_nexus clear_nexus; | ||
639 | struct initiate_ssp_tmf ssp_tmf; | ||
640 | }; | ||
641 | } __attribute__ ((packed)); | ||
642 | |||
643 | /* ---------- Done List ---------- */ | ||
644 | /* The done list entry opcode field is defined below. | ||
645 | * The mnemonic encoding and meaning is as follows: | ||
646 | * TC - Task Complete, status was received and acknowledged | ||
647 | * TF - Task Failed, indicates an error prior to receiving acknowledgment | ||
648 | * for the command: | ||
649 | * - no conn, | ||
650 | * - NACK or R_ERR received in response to this command, | ||
651 | * - credit blocked or not available, or in the case of SMP request, | ||
652 | * - no SMP response was received. | ||
653 | * In these four cases it is known that the target didn't receive the | ||
654 | * command. | ||
655 | * TI - Task Interrupted, error after the command was acknowledged. It is | ||
656 | * known that the command was received by the target. | ||
657 | * TU - Task Unacked, command was transmitted but neither ACK (R_OK) nor NAK | ||
658 | * (R_ERR) was received due to loss of signal, broken connection, loss of | ||
659 | * dword sync or other reason. The application client should send the | ||
660 | * appropriate task query. | ||
661 | * TA - Task Aborted, see TF. | ||
662 | * _RESP - The completion includes an empty buffer containing status. | ||
663 | * TO - Timeout. | ||
664 | */ | ||
665 | #define TC_NO_ERROR 0x00 | ||
666 | #define TC_UNDERRUN 0x01 | ||
667 | #define TC_OVERRUN 0x02 | ||
668 | #define TF_OPEN_TO 0x03 | ||
669 | #define TF_OPEN_REJECT 0x04 | ||
670 | #define TI_BREAK 0x05 | ||
671 | #define TI_PROTO_ERR 0x06 | ||
672 | #define TC_SSP_RESP 0x07 | ||
673 | #define TI_PHY_DOWN 0x08 | ||
674 | #define TF_PHY_DOWN 0x09 | ||
675 | #define TC_LINK_ADM_RESP 0x0a | ||
676 | #define TC_CSMI 0x0b | ||
677 | #define TC_ATA_RESP 0x0c | ||
678 | #define TU_PHY_DOWN 0x0d | ||
679 | #define TU_BREAK 0x0e | ||
680 | #define TI_SATA_TO 0x0f | ||
681 | #define TI_NAK 0x10 | ||
682 | #define TC_CONTROL_PHY 0x11 | ||
683 | #define TF_BREAK 0x12 | ||
684 | #define TC_RESUME 0x13 | ||
685 | #define TI_ACK_NAK_TO 0x14 | ||
686 | #define TF_SMPRSP_TO 0x15 | ||
687 | #define TF_SMP_XMIT_RCV_ERR 0x16 | ||
688 | #define TC_PARTIAL_SG_LIST 0x17 | ||
689 | #define TU_ACK_NAK_TO 0x18 | ||
690 | #define TU_SATA_TO 0x19 | ||
691 | #define TF_NAK_RECV 0x1a | ||
692 | #define TA_I_T_NEXUS_LOSS 0x1b | ||
693 | #define TC_ATA_R_ERR_RECV 0x1c | ||
694 | #define TF_TMF_NO_CTX 0x1d | ||
695 | #define TA_ON_REQ 0x1e | ||
696 | #define TF_TMF_NO_TAG 0x1f | ||
697 | #define TF_TMF_TAG_FREE 0x20 | ||
698 | #define TF_TMF_TASK_DONE 0x21 | ||
699 | #define TF_TMF_NO_CONN_HANDLE 0x22 | ||
700 | #define TC_TASK_CLEARED 0x23 | ||
701 | #define TI_SYNCS_RECV 0x24 | ||
702 | #define TU_SYNCS_RECV 0x25 | ||
703 | #define TF_IRTT_TO 0x26 | ||
704 | #define TF_NO_SMP_CONN 0x27 | ||
705 | #define TF_IU_SHORT 0x28 | ||
706 | #define TF_DATA_OFFS_ERR 0x29 | ||
707 | #define TF_INV_CONN_HANDLE 0x2a | ||
708 | #define TF_REQUESTED_N_PENDING 0x2b | ||
709 | |||
710 | /* 0xc1 - 0xc7: empty buffer received, | ||
711 | 0xd1 - 0xd7: establish nexus empty buffer received | ||
712 | */ | ||
713 | /* This is the ESCB mask */ | ||
714 | #define ESCB_RECVD 0xC0 | ||
715 | |||
716 | |||
717 | /* This struct done_list_struct defines the done list entry. | ||
718 | * All fields are LE. | ||
719 | */ | ||
720 | struct done_list_struct { | ||
721 | __le16 index; /* aka transaction context */ | ||
722 | u8 opcode; | ||
723 | u8 status_block[4]; | ||
724 | u8 toggle; /* bit 0 */ | ||
725 | #define DL_TOGGLE_MASK 0x01 | ||
726 | } __attribute__ ((packed)); | ||
727 | |||
728 | /* ---------- PHYS ---------- */ | ||
729 | |||
730 | struct asd_phy { | ||
731 | struct asd_sas_phy sas_phy; | ||
732 | struct asd_phy_desc *phy_desc; /* hw profile */ | ||
733 | |||
734 | struct sas_identify_frame *identify_frame; | ||
735 | struct asd_dma_tok *id_frm_tok; | ||
736 | |||
737 | u8 frame_rcvd[ASD_EDB_SIZE]; | ||
738 | }; | ||
739 | |||
740 | |||
741 | #define ASD_SCB_SIZE sizeof(struct scb) | ||
742 | #define ASD_DDB_SIZE sizeof(struct asd_ddb_ssp_smp_target_port) | ||
743 | |||
744 | /* Define this to 0 if you do not want NOTIFY (ENABLE SPINIP) sent. | ||
745 | * Default: 0x10 (it's a mask) | ||
746 | */ | ||
747 | #define ASD_NOTIFY_ENABLE_SPINUP 0x10 | ||
748 | |||
749 | /* If enabled, set this to the interval between transmission | ||
750 | * of NOTIFY (ENABLE SPINUP). In units of 200 us. | ||
751 | */ | ||
752 | #define ASD_NOTIFY_TIMEOUT 2500 | ||
753 | |||
754 | /* Initial delay after OOB, before we transmit NOTIFY (ENABLE SPINUP). | ||
755 | * If 0, transmit immediately. In milliseconds. | ||
756 | */ | ||
757 | #define ASD_NOTIFY_DOWN_COUNT 0 | ||
758 | |||
759 | /* Device present timer timeout constant, 10 ms. */ | ||
760 | #define ASD_DEV_PRESENT_TIMEOUT 0x2710 | ||
761 | |||
762 | #define ASD_SATA_INTERLOCK_TIMEOUT 0 | ||
763 | |||
764 | /* How long to wait before shutting down an STP connection, unless | ||
765 | * an STP target sent frame(s). 50 usec. | ||
766 | * IGNORED by the sequencer (i.e. value 0 always). | ||
767 | */ | ||
768 | #define ASD_STP_SHUTDOWN_TIMEOUT 0x0 | ||
769 | |||
770 | /* ATA soft reset timer timeout. 5 usec. */ | ||
771 | #define ASD_SRST_ASSERT_TIMEOUT 0x05 | ||
772 | |||
773 | /* 31 sec */ | ||
774 | #define ASD_RCV_FIS_TIMEOUT 0x01D905C0 | ||
775 | |||
776 | #define ASD_ONE_MILLISEC_TIMEOUT 0x03e8 | ||
777 | |||
778 | /* COMINIT timer */ | ||
779 | #define ASD_TEN_MILLISEC_TIMEOUT 0x2710 | ||
780 | #define ASD_COMINIT_TIMEOUT ASD_TEN_MILLISEC_TIMEOUT | ||
781 | |||
782 | /* 1 sec */ | ||
783 | #define ASD_SMP_RCV_TIMEOUT 0x000F4240 | ||
784 | |||
785 | #endif | ||
diff --git a/drivers/scsi/aic94xx/aic94xx_scb.c b/drivers/scsi/aic94xx/aic94xx_scb.c new file mode 100644 index 000000000000..fc1b7438a913 --- /dev/null +++ b/drivers/scsi/aic94xx/aic94xx_scb.c | |||
@@ -0,0 +1,732 @@ | |||
1 | /* | ||
2 | * Aic94xx SAS/SATA driver SCB management. | ||
3 | * | ||
4 | * Copyright (C) 2005 Adaptec, Inc. All rights reserved. | ||
5 | * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> | ||
6 | * | ||
7 | * This file is licensed under GPLv2. | ||
8 | * | ||
9 | * This file is part of the aic94xx driver. | ||
10 | * | ||
11 | * The aic94xx driver is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License as | ||
13 | * published by the Free Software Foundation; version 2 of the | ||
14 | * License. | ||
15 | * | ||
16 | * The aic94xx driver is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
19 | * General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with the aic94xx driver; if not, write to the Free Software | ||
23 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #include <linux/pci.h> | ||
28 | |||
29 | #include "aic94xx.h" | ||
30 | #include "aic94xx_reg.h" | ||
31 | #include "aic94xx_hwi.h" | ||
32 | #include "aic94xx_seq.h" | ||
33 | |||
34 | #include "aic94xx_dump.h" | ||
35 | |||
36 | /* ---------- EMPTY SCB ---------- */ | ||
37 | |||
38 | #define DL_PHY_MASK 7 | ||
39 | #define BYTES_DMAED 0 | ||
40 | #define PRIMITIVE_RECVD 0x08 | ||
41 | #define PHY_EVENT 0x10 | ||
42 | #define LINK_RESET_ERROR 0x18 | ||
43 | #define TIMER_EVENT 0x20 | ||
44 | #define REQ_TASK_ABORT 0xF0 | ||
45 | #define REQ_DEVICE_RESET 0xF1 | ||
46 | #define SIGNAL_NCQ_ERROR 0xF2 | ||
47 | #define CLEAR_NCQ_ERROR 0xF3 | ||
48 | |||
49 | #define PHY_EVENTS_STATUS (CURRENT_LOSS_OF_SIGNAL | CURRENT_OOB_DONE \ | ||
50 | | CURRENT_SPINUP_HOLD | CURRENT_GTO_TIMEOUT \ | ||
51 | | CURRENT_OOB_ERROR) | ||
52 | |||
53 | static inline void get_lrate_mode(struct asd_phy *phy, u8 oob_mode) | ||
54 | { | ||
55 | switch (oob_mode & 7) { | ||
56 | case PHY_SPEED_60: | ||
57 | /* FIXME: sas transport class doesn't have this */ | ||
58 | phy->sas_phy.linkrate = PHY_LINKRATE_6; | ||
59 | phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_6_0_GBPS; | ||
60 | break; | ||
61 | case PHY_SPEED_30: | ||
62 | phy->sas_phy.linkrate = PHY_LINKRATE_3; | ||
63 | phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS; | ||
64 | break; | ||
65 | case PHY_SPEED_15: | ||
66 | phy->sas_phy.linkrate = PHY_LINKRATE_1_5; | ||
67 | phy->sas_phy.phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS; | ||
68 | break; | ||
69 | } | ||
70 | if (oob_mode & SAS_MODE) | ||
71 | phy->sas_phy.oob_mode = SAS_OOB_MODE; | ||
72 | else if (oob_mode & SATA_MODE) | ||
73 | phy->sas_phy.oob_mode = SATA_OOB_MODE; | ||
74 | } | ||
75 | |||
76 | static inline void asd_phy_event_tasklet(struct asd_ascb *ascb, | ||
77 | struct done_list_struct *dl) | ||
78 | { | ||
79 | struct asd_ha_struct *asd_ha = ascb->ha; | ||
80 | struct sas_ha_struct *sas_ha = &asd_ha->sas_ha; | ||
81 | int phy_id = dl->status_block[0] & DL_PHY_MASK; | ||
82 | struct asd_phy *phy = &asd_ha->phys[phy_id]; | ||
83 | |||
84 | u8 oob_status = dl->status_block[1] & PHY_EVENTS_STATUS; | ||
85 | u8 oob_mode = dl->status_block[2]; | ||
86 | |||
87 | switch (oob_status) { | ||
88 | case CURRENT_LOSS_OF_SIGNAL: | ||
89 | /* directly attached device was removed */ | ||
90 | ASD_DPRINTK("phy%d: device unplugged\n", phy_id); | ||
91 | asd_turn_led(asd_ha, phy_id, 0); | ||
92 | sas_phy_disconnected(&phy->sas_phy); | ||
93 | sas_ha->notify_phy_event(&phy->sas_phy, PHYE_LOSS_OF_SIGNAL); | ||
94 | break; | ||
95 | case CURRENT_OOB_DONE: | ||
96 | /* hot plugged device */ | ||
97 | asd_turn_led(asd_ha, phy_id, 1); | ||
98 | get_lrate_mode(phy, oob_mode); | ||
99 | ASD_DPRINTK("phy%d device plugged: lrate:0x%x, proto:0x%x\n", | ||
100 | phy_id, phy->sas_phy.linkrate, phy->sas_phy.iproto); | ||
101 | sas_ha->notify_phy_event(&phy->sas_phy, PHYE_OOB_DONE); | ||
102 | break; | ||
103 | case CURRENT_SPINUP_HOLD: | ||
104 | /* hot plug SATA, no COMWAKE sent */ | ||
105 | asd_turn_led(asd_ha, phy_id, 1); | ||
106 | sas_ha->notify_phy_event(&phy->sas_phy, PHYE_SPINUP_HOLD); | ||
107 | break; | ||
108 | case CURRENT_GTO_TIMEOUT: | ||
109 | case CURRENT_OOB_ERROR: | ||
110 | ASD_DPRINTK("phy%d error while OOB: oob status:0x%x\n", phy_id, | ||
111 | dl->status_block[1]); | ||
112 | asd_turn_led(asd_ha, phy_id, 0); | ||
113 | sas_phy_disconnected(&phy->sas_phy); | ||
114 | sas_ha->notify_phy_event(&phy->sas_phy, PHYE_OOB_ERROR); | ||
115 | break; | ||
116 | } | ||
117 | } | ||
118 | |||
119 | /* If phys are enabled sparsely, this will do the right thing. */ | ||
120 | static inline unsigned ord_phy(struct asd_ha_struct *asd_ha, | ||
121 | struct asd_phy *phy) | ||
122 | { | ||
123 | u8 enabled_mask = asd_ha->hw_prof.enabled_phys; | ||
124 | int i, k = 0; | ||
125 | |||
126 | for_each_phy(enabled_mask, enabled_mask, i) { | ||
127 | if (&asd_ha->phys[i] == phy) | ||
128 | return k; | ||
129 | k++; | ||
130 | } | ||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | /** | ||
135 | * asd_get_attached_sas_addr -- extract/generate attached SAS address | ||
136 | * phy: pointer to asd_phy | ||
137 | * sas_addr: pointer to buffer where the SAS address is to be written | ||
138 | * | ||
139 | * This function extracts the SAS address from an IDENTIFY frame | ||
140 | * received. If OOB is SATA, then a SAS address is generated from the | ||
141 | * HA tables. | ||
142 | * | ||
143 | * LOCKING: the frame_rcvd_lock needs to be held since this parses the frame | ||
144 | * buffer. | ||
145 | */ | ||
146 | static inline void asd_get_attached_sas_addr(struct asd_phy *phy, u8 *sas_addr) | ||
147 | { | ||
148 | if (phy->sas_phy.frame_rcvd[0] == 0x34 | ||
149 | && phy->sas_phy.oob_mode == SATA_OOB_MODE) { | ||
150 | struct asd_ha_struct *asd_ha = phy->sas_phy.ha->lldd_ha; | ||
151 | /* FIS device-to-host */ | ||
152 | u64 addr = be64_to_cpu(*(__be64 *)phy->phy_desc->sas_addr); | ||
153 | |||
154 | addr += asd_ha->hw_prof.sata_name_base + ord_phy(asd_ha, phy); | ||
155 | *(__be64 *)sas_addr = cpu_to_be64(addr); | ||
156 | } else { | ||
157 | struct sas_identify_frame *idframe = | ||
158 | (void *) phy->sas_phy.frame_rcvd; | ||
159 | memcpy(sas_addr, idframe->sas_addr, SAS_ADDR_SIZE); | ||
160 | } | ||
161 | } | ||
162 | |||
163 | static inline void asd_bytes_dmaed_tasklet(struct asd_ascb *ascb, | ||
164 | struct done_list_struct *dl, | ||
165 | int edb_id, int phy_id) | ||
166 | { | ||
167 | unsigned long flags; | ||
168 | int edb_el = edb_id + ascb->edb_index; | ||
169 | struct asd_dma_tok *edb = ascb->ha->seq.edb_arr[edb_el]; | ||
170 | struct asd_phy *phy = &ascb->ha->phys[phy_id]; | ||
171 | struct sas_ha_struct *sas_ha = phy->sas_phy.ha; | ||
172 | u16 size = ((dl->status_block[3] & 7) << 8) | dl->status_block[2]; | ||
173 | |||
174 | size = min(size, (u16) sizeof(phy->frame_rcvd)); | ||
175 | |||
176 | spin_lock_irqsave(&phy->sas_phy.frame_rcvd_lock, flags); | ||
177 | memcpy(phy->sas_phy.frame_rcvd, edb->vaddr, size); | ||
178 | phy->sas_phy.frame_rcvd_size = size; | ||
179 | asd_get_attached_sas_addr(phy, phy->sas_phy.attached_sas_addr); | ||
180 | spin_unlock_irqrestore(&phy->sas_phy.frame_rcvd_lock, flags); | ||
181 | asd_dump_frame_rcvd(phy, dl); | ||
182 | sas_ha->notify_port_event(&phy->sas_phy, PORTE_BYTES_DMAED); | ||
183 | } | ||
184 | |||
185 | static inline void asd_link_reset_err_tasklet(struct asd_ascb *ascb, | ||
186 | struct done_list_struct *dl, | ||
187 | int phy_id) | ||
188 | { | ||
189 | struct asd_ha_struct *asd_ha = ascb->ha; | ||
190 | struct sas_ha_struct *sas_ha = &asd_ha->sas_ha; | ||
191 | struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id]; | ||
192 | u8 lr_error = dl->status_block[1]; | ||
193 | u8 retries_left = dl->status_block[2]; | ||
194 | |||
195 | switch (lr_error) { | ||
196 | case 0: | ||
197 | ASD_DPRINTK("phy%d: Receive ID timer expired\n", phy_id); | ||
198 | break; | ||
199 | case 1: | ||
200 | ASD_DPRINTK("phy%d: Loss of signal\n", phy_id); | ||
201 | break; | ||
202 | case 2: | ||
203 | ASD_DPRINTK("phy%d: Loss of dword sync\n", phy_id); | ||
204 | break; | ||
205 | case 3: | ||
206 | ASD_DPRINTK("phy%d: Receive FIS timeout\n", phy_id); | ||
207 | break; | ||
208 | default: | ||
209 | ASD_DPRINTK("phy%d: unknown link reset error code: 0x%x\n", | ||
210 | phy_id, lr_error); | ||
211 | break; | ||
212 | } | ||
213 | |||
214 | asd_turn_led(asd_ha, phy_id, 0); | ||
215 | sas_phy_disconnected(sas_phy); | ||
216 | sas_ha->notify_port_event(sas_phy, PORTE_LINK_RESET_ERR); | ||
217 | |||
218 | if (retries_left == 0) { | ||
219 | int num = 1; | ||
220 | struct asd_ascb *cp = asd_ascb_alloc_list(ascb->ha, &num, | ||
221 | GFP_ATOMIC); | ||
222 | if (!cp) { | ||
223 | asd_printk("%s: out of memory\n", __FUNCTION__); | ||
224 | goto out; | ||
225 | } | ||
226 | ASD_DPRINTK("phy%d: retries:0 performing link reset seq\n", | ||
227 | phy_id); | ||
228 | asd_build_control_phy(cp, phy_id, ENABLE_PHY); | ||
229 | if (asd_post_ascb_list(ascb->ha, cp, 1) != 0) | ||
230 | asd_ascb_free(cp); | ||
231 | } | ||
232 | out: | ||
233 | ; | ||
234 | } | ||
235 | |||
236 | static inline void asd_primitive_rcvd_tasklet(struct asd_ascb *ascb, | ||
237 | struct done_list_struct *dl, | ||
238 | int phy_id) | ||
239 | { | ||
240 | unsigned long flags; | ||
241 | struct sas_ha_struct *sas_ha = &ascb->ha->sas_ha; | ||
242 | struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id]; | ||
243 | u8 reg = dl->status_block[1]; | ||
244 | u32 cont = dl->status_block[2] << ((reg & 3)*8); | ||
245 | |||
246 | reg &= ~3; | ||
247 | switch (reg) { | ||
248 | case LmPRMSTAT0BYTE0: | ||
249 | switch (cont) { | ||
250 | case LmBROADCH: | ||
251 | case LmBROADRVCH0: | ||
252 | case LmBROADRVCH1: | ||
253 | case LmBROADSES: | ||
254 | ASD_DPRINTK("phy%d: BROADCAST change received:%d\n", | ||
255 | phy_id, cont); | ||
256 | spin_lock_irqsave(&sas_phy->sas_prim_lock, flags); | ||
257 | sas_phy->sas_prim = ffs(cont); | ||
258 | spin_unlock_irqrestore(&sas_phy->sas_prim_lock, flags); | ||
259 | sas_ha->notify_port_event(sas_phy,PORTE_BROADCAST_RCVD); | ||
260 | break; | ||
261 | |||
262 | case LmUNKNOWNP: | ||
263 | ASD_DPRINTK("phy%d: unknown BREAK\n", phy_id); | ||
264 | break; | ||
265 | |||
266 | default: | ||
267 | ASD_DPRINTK("phy%d: primitive reg:0x%x, cont:0x%04x\n", | ||
268 | phy_id, reg, cont); | ||
269 | break; | ||
270 | } | ||
271 | break; | ||
272 | case LmPRMSTAT1BYTE0: | ||
273 | switch (cont) { | ||
274 | case LmHARDRST: | ||
275 | ASD_DPRINTK("phy%d: HARD_RESET primitive rcvd\n", | ||
276 | phy_id); | ||
277 | /* The sequencer disables all phys on that port. | ||
278 | * We have to re-enable the phys ourselves. */ | ||
279 | sas_ha->notify_port_event(sas_phy, PORTE_HARD_RESET); | ||
280 | break; | ||
281 | |||
282 | default: | ||
283 | ASD_DPRINTK("phy%d: primitive reg:0x%x, cont:0x%04x\n", | ||
284 | phy_id, reg, cont); | ||
285 | break; | ||
286 | } | ||
287 | break; | ||
288 | default: | ||
289 | ASD_DPRINTK("unknown primitive register:0x%x\n", | ||
290 | dl->status_block[1]); | ||
291 | break; | ||
292 | } | ||
293 | } | ||
294 | |||
295 | /** | ||
296 | * asd_invalidate_edb -- invalidate an EDB and if necessary post the ESCB | ||
297 | * @ascb: pointer to Empty SCB | ||
298 | * @edb_id: index [0,6] to the empty data buffer which is to be invalidated | ||
299 | * | ||
300 | * After an EDB has been invalidated, if all EDBs in this ESCB have been | ||
301 | * invalidated, the ESCB is posted back to the sequencer. | ||
302 | * Context is tasklet/IRQ. | ||
303 | */ | ||
304 | void asd_invalidate_edb(struct asd_ascb *ascb, int edb_id) | ||
305 | { | ||
306 | struct asd_seq_data *seq = &ascb->ha->seq; | ||
307 | struct empty_scb *escb = &ascb->scb->escb; | ||
308 | struct sg_el *eb = &escb->eb[edb_id]; | ||
309 | struct asd_dma_tok *edb = seq->edb_arr[ascb->edb_index + edb_id]; | ||
310 | |||
311 | memset(edb->vaddr, 0, ASD_EDB_SIZE); | ||
312 | eb->flags |= ELEMENT_NOT_VALID; | ||
313 | escb->num_valid--; | ||
314 | |||
315 | if (escb->num_valid == 0) { | ||
316 | int i; | ||
317 | /* ASD_DPRINTK("reposting escb: vaddr: 0x%p, " | ||
318 | "dma_handle: 0x%08llx, next: 0x%08llx, " | ||
319 | "index:%d, opcode:0x%02x\n", | ||
320 | ascb->dma_scb.vaddr, | ||
321 | (u64)ascb->dma_scb.dma_handle, | ||
322 | le64_to_cpu(ascb->scb->header.next_scb), | ||
323 | le16_to_cpu(ascb->scb->header.index), | ||
324 | ascb->scb->header.opcode); | ||
325 | */ | ||
326 | escb->num_valid = ASD_EDBS_PER_SCB; | ||
327 | for (i = 0; i < ASD_EDBS_PER_SCB; i++) | ||
328 | escb->eb[i].flags = 0; | ||
329 | if (!list_empty(&ascb->list)) | ||
330 | list_del_init(&ascb->list); | ||
331 | i = asd_post_escb_list(ascb->ha, ascb, 1); | ||
332 | if (i) | ||
333 | asd_printk("couldn't post escb, err:%d\n", i); | ||
334 | } | ||
335 | } | ||
336 | |||
337 | static void escb_tasklet_complete(struct asd_ascb *ascb, | ||
338 | struct done_list_struct *dl) | ||
339 | { | ||
340 | struct asd_ha_struct *asd_ha = ascb->ha; | ||
341 | struct sas_ha_struct *sas_ha = &asd_ha->sas_ha; | ||
342 | int edb = (dl->opcode & DL_PHY_MASK) - 1; /* [0xc1,0xc7] -> [0,6] */ | ||
343 | u8 sb_opcode = dl->status_block[0]; | ||
344 | int phy_id = sb_opcode & DL_PHY_MASK; | ||
345 | struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id]; | ||
346 | |||
347 | if (edb > 6 || edb < 0) { | ||
348 | ASD_DPRINTK("edb is 0x%x! dl->opcode is 0x%x\n", | ||
349 | edb, dl->opcode); | ||
350 | ASD_DPRINTK("sb_opcode : 0x%x, phy_id: 0x%x\n", | ||
351 | sb_opcode, phy_id); | ||
352 | ASD_DPRINTK("escb: vaddr: 0x%p, " | ||
353 | "dma_handle: 0x%llx, next: 0x%llx, " | ||
354 | "index:%d, opcode:0x%02x\n", | ||
355 | ascb->dma_scb.vaddr, | ||
356 | (unsigned long long)ascb->dma_scb.dma_handle, | ||
357 | (unsigned long long) | ||
358 | le64_to_cpu(ascb->scb->header.next_scb), | ||
359 | le16_to_cpu(ascb->scb->header.index), | ||
360 | ascb->scb->header.opcode); | ||
361 | } | ||
362 | |||
363 | sb_opcode &= ~DL_PHY_MASK; | ||
364 | |||
365 | switch (sb_opcode) { | ||
366 | case BYTES_DMAED: | ||
367 | ASD_DPRINTK("%s: phy%d: BYTES_DMAED\n", __FUNCTION__, phy_id); | ||
368 | asd_bytes_dmaed_tasklet(ascb, dl, edb, phy_id); | ||
369 | break; | ||
370 | case PRIMITIVE_RECVD: | ||
371 | ASD_DPRINTK("%s: phy%d: PRIMITIVE_RECVD\n", __FUNCTION__, | ||
372 | phy_id); | ||
373 | asd_primitive_rcvd_tasklet(ascb, dl, phy_id); | ||
374 | break; | ||
375 | case PHY_EVENT: | ||
376 | ASD_DPRINTK("%s: phy%d: PHY_EVENT\n", __FUNCTION__, phy_id); | ||
377 | asd_phy_event_tasklet(ascb, dl); | ||
378 | break; | ||
379 | case LINK_RESET_ERROR: | ||
380 | ASD_DPRINTK("%s: phy%d: LINK_RESET_ERROR\n", __FUNCTION__, | ||
381 | phy_id); | ||
382 | asd_link_reset_err_tasklet(ascb, dl, phy_id); | ||
383 | break; | ||
384 | case TIMER_EVENT: | ||
385 | ASD_DPRINTK("%s: phy%d: TIMER_EVENT, lost dw sync\n", | ||
386 | __FUNCTION__, phy_id); | ||
387 | asd_turn_led(asd_ha, phy_id, 0); | ||
388 | /* the device is gone */ | ||
389 | sas_phy_disconnected(sas_phy); | ||
390 | sas_ha->notify_port_event(sas_phy, PORTE_TIMER_EVENT); | ||
391 | break; | ||
392 | case REQ_TASK_ABORT: | ||
393 | ASD_DPRINTK("%s: phy%d: REQ_TASK_ABORT\n", __FUNCTION__, | ||
394 | phy_id); | ||
395 | break; | ||
396 | case REQ_DEVICE_RESET: | ||
397 | ASD_DPRINTK("%s: phy%d: REQ_DEVICE_RESET\n", __FUNCTION__, | ||
398 | phy_id); | ||
399 | break; | ||
400 | case SIGNAL_NCQ_ERROR: | ||
401 | ASD_DPRINTK("%s: phy%d: SIGNAL_NCQ_ERROR\n", __FUNCTION__, | ||
402 | phy_id); | ||
403 | break; | ||
404 | case CLEAR_NCQ_ERROR: | ||
405 | ASD_DPRINTK("%s: phy%d: CLEAR_NCQ_ERROR\n", __FUNCTION__, | ||
406 | phy_id); | ||
407 | break; | ||
408 | default: | ||
409 | ASD_DPRINTK("%s: phy%d: unknown event:0x%x\n", __FUNCTION__, | ||
410 | phy_id, sb_opcode); | ||
411 | ASD_DPRINTK("edb is 0x%x! dl->opcode is 0x%x\n", | ||
412 | edb, dl->opcode); | ||
413 | ASD_DPRINTK("sb_opcode : 0x%x, phy_id: 0x%x\n", | ||
414 | sb_opcode, phy_id); | ||
415 | ASD_DPRINTK("escb: vaddr: 0x%p, " | ||
416 | "dma_handle: 0x%llx, next: 0x%llx, " | ||
417 | "index:%d, opcode:0x%02x\n", | ||
418 | ascb->dma_scb.vaddr, | ||
419 | (unsigned long long)ascb->dma_scb.dma_handle, | ||
420 | (unsigned long long) | ||
421 | le64_to_cpu(ascb->scb->header.next_scb), | ||
422 | le16_to_cpu(ascb->scb->header.index), | ||
423 | ascb->scb->header.opcode); | ||
424 | |||
425 | break; | ||
426 | } | ||
427 | |||
428 | asd_invalidate_edb(ascb, edb); | ||
429 | } | ||
430 | |||
431 | int asd_init_post_escbs(struct asd_ha_struct *asd_ha) | ||
432 | { | ||
433 | struct asd_seq_data *seq = &asd_ha->seq; | ||
434 | int i; | ||
435 | |||
436 | for (i = 0; i < seq->num_escbs; i++) | ||
437 | seq->escb_arr[i]->tasklet_complete = escb_tasklet_complete; | ||
438 | |||
439 | ASD_DPRINTK("posting %d escbs\n", i); | ||
440 | return asd_post_escb_list(asd_ha, seq->escb_arr[0], seq->num_escbs); | ||
441 | } | ||
442 | |||
443 | /* ---------- CONTROL PHY ---------- */ | ||
444 | |||
445 | #define CONTROL_PHY_STATUS (CURRENT_DEVICE_PRESENT | CURRENT_OOB_DONE \ | ||
446 | | CURRENT_SPINUP_HOLD | CURRENT_GTO_TIMEOUT \ | ||
447 | | CURRENT_OOB_ERROR) | ||
448 | |||
449 | /** | ||
450 | * control_phy_tasklet_complete -- tasklet complete for CONTROL PHY ascb | ||
451 | * @ascb: pointer to an ascb | ||
452 | * @dl: pointer to the done list entry | ||
453 | * | ||
454 | * This function completes a CONTROL PHY scb and frees the ascb. | ||
455 | * A note on LEDs: | ||
456 | * - an LED blinks if there is IO though it, | ||
457 | * - if a device is connected to the LED, it is lit, | ||
458 | * - if no device is connected to the LED, is is dimmed (off). | ||
459 | */ | ||
460 | static void control_phy_tasklet_complete(struct asd_ascb *ascb, | ||
461 | struct done_list_struct *dl) | ||
462 | { | ||
463 | struct asd_ha_struct *asd_ha = ascb->ha; | ||
464 | struct scb *scb = ascb->scb; | ||
465 | struct control_phy *control_phy = &scb->control_phy; | ||
466 | u8 phy_id = control_phy->phy_id; | ||
467 | struct asd_phy *phy = &ascb->ha->phys[phy_id]; | ||
468 | |||
469 | u8 status = dl->status_block[0]; | ||
470 | u8 oob_status = dl->status_block[1]; | ||
471 | u8 oob_mode = dl->status_block[2]; | ||
472 | /* u8 oob_signals= dl->status_block[3]; */ | ||
473 | |||
474 | if (status != 0) { | ||
475 | ASD_DPRINTK("%s: phy%d status block opcode:0x%x\n", | ||
476 | __FUNCTION__, phy_id, status); | ||
477 | goto out; | ||
478 | } | ||
479 | |||
480 | switch (control_phy->sub_func) { | ||
481 | case DISABLE_PHY: | ||
482 | asd_ha->hw_prof.enabled_phys &= ~(1 << phy_id); | ||
483 | asd_turn_led(asd_ha, phy_id, 0); | ||
484 | asd_control_led(asd_ha, phy_id, 0); | ||
485 | ASD_DPRINTK("%s: disable phy%d\n", __FUNCTION__, phy_id); | ||
486 | break; | ||
487 | |||
488 | case ENABLE_PHY: | ||
489 | asd_control_led(asd_ha, phy_id, 1); | ||
490 | if (oob_status & CURRENT_OOB_DONE) { | ||
491 | asd_ha->hw_prof.enabled_phys |= (1 << phy_id); | ||
492 | get_lrate_mode(phy, oob_mode); | ||
493 | asd_turn_led(asd_ha, phy_id, 1); | ||
494 | ASD_DPRINTK("%s: phy%d, lrate:0x%x, proto:0x%x\n", | ||
495 | __FUNCTION__, phy_id,phy->sas_phy.linkrate, | ||
496 | phy->sas_phy.iproto); | ||
497 | } else if (oob_status & CURRENT_SPINUP_HOLD) { | ||
498 | asd_ha->hw_prof.enabled_phys |= (1 << phy_id); | ||
499 | asd_turn_led(asd_ha, phy_id, 1); | ||
500 | ASD_DPRINTK("%s: phy%d, spinup hold\n", __FUNCTION__, | ||
501 | phy_id); | ||
502 | } else if (oob_status & CURRENT_ERR_MASK) { | ||
503 | asd_turn_led(asd_ha, phy_id, 0); | ||
504 | ASD_DPRINTK("%s: phy%d: error: oob status:0x%02x\n", | ||
505 | __FUNCTION__, phy_id, oob_status); | ||
506 | } else if (oob_status & (CURRENT_HOT_PLUG_CNCT | ||
507 | | CURRENT_DEVICE_PRESENT)) { | ||
508 | asd_ha->hw_prof.enabled_phys |= (1 << phy_id); | ||
509 | asd_turn_led(asd_ha, phy_id, 1); | ||
510 | ASD_DPRINTK("%s: phy%d: hot plug or device present\n", | ||
511 | __FUNCTION__, phy_id); | ||
512 | } else { | ||
513 | asd_ha->hw_prof.enabled_phys |= (1 << phy_id); | ||
514 | asd_turn_led(asd_ha, phy_id, 0); | ||
515 | ASD_DPRINTK("%s: phy%d: no device present: " | ||
516 | "oob_status:0x%x\n", | ||
517 | __FUNCTION__, phy_id, oob_status); | ||
518 | } | ||
519 | break; | ||
520 | case RELEASE_SPINUP_HOLD: | ||
521 | case PHY_NO_OP: | ||
522 | case EXECUTE_HARD_RESET: | ||
523 | ASD_DPRINTK("%s: phy%d: sub_func:0x%x\n", __FUNCTION__, | ||
524 | phy_id, control_phy->sub_func); | ||
525 | /* XXX finish */ | ||
526 | break; | ||
527 | default: | ||
528 | ASD_DPRINTK("%s: phy%d: sub_func:0x%x?\n", __FUNCTION__, | ||
529 | phy_id, control_phy->sub_func); | ||
530 | break; | ||
531 | } | ||
532 | out: | ||
533 | asd_ascb_free(ascb); | ||
534 | } | ||
535 | |||
536 | static inline void set_speed_mask(u8 *speed_mask, struct asd_phy_desc *pd) | ||
537 | { | ||
538 | /* disable all speeds, then enable defaults */ | ||
539 | *speed_mask = SAS_SPEED_60_DIS | SAS_SPEED_30_DIS | SAS_SPEED_15_DIS | ||
540 | | SATA_SPEED_30_DIS | SATA_SPEED_15_DIS; | ||
541 | |||
542 | switch (pd->max_sas_lrate) { | ||
543 | case PHY_LINKRATE_6: | ||
544 | *speed_mask &= ~SAS_SPEED_60_DIS; | ||
545 | default: | ||
546 | case PHY_LINKRATE_3: | ||
547 | *speed_mask &= ~SAS_SPEED_30_DIS; | ||
548 | case PHY_LINKRATE_1_5: | ||
549 | *speed_mask &= ~SAS_SPEED_15_DIS; | ||
550 | } | ||
551 | |||
552 | switch (pd->min_sas_lrate) { | ||
553 | case PHY_LINKRATE_6: | ||
554 | *speed_mask |= SAS_SPEED_30_DIS; | ||
555 | case PHY_LINKRATE_3: | ||
556 | *speed_mask |= SAS_SPEED_15_DIS; | ||
557 | default: | ||
558 | case PHY_LINKRATE_1_5: | ||
559 | /* nothing to do */ | ||
560 | ; | ||
561 | } | ||
562 | |||
563 | switch (pd->max_sata_lrate) { | ||
564 | case PHY_LINKRATE_3: | ||
565 | *speed_mask &= ~SATA_SPEED_30_DIS; | ||
566 | default: | ||
567 | case PHY_LINKRATE_1_5: | ||
568 | *speed_mask &= ~SATA_SPEED_15_DIS; | ||
569 | } | ||
570 | |||
571 | switch (pd->min_sata_lrate) { | ||
572 | case PHY_LINKRATE_3: | ||
573 | *speed_mask |= SATA_SPEED_15_DIS; | ||
574 | default: | ||
575 | case PHY_LINKRATE_1_5: | ||
576 | /* nothing to do */ | ||
577 | ; | ||
578 | } | ||
579 | } | ||
580 | |||
581 | /** | ||
582 | * asd_build_control_phy -- build a CONTROL PHY SCB | ||
583 | * @ascb: pointer to an ascb | ||
584 | * @phy_id: phy id to control, integer | ||
585 | * @subfunc: subfunction, what to actually to do the phy | ||
586 | * | ||
587 | * This function builds a CONTROL PHY scb. No allocation of any kind | ||
588 | * is performed. @ascb is allocated with the list function. | ||
589 | * The caller can override the ascb->tasklet_complete to point | ||
590 | * to its own callback function. It must call asd_ascb_free() | ||
591 | * at its tasklet complete function. | ||
592 | * See the default implementation. | ||
593 | */ | ||
594 | void asd_build_control_phy(struct asd_ascb *ascb, int phy_id, u8 subfunc) | ||
595 | { | ||
596 | struct asd_phy *phy = &ascb->ha->phys[phy_id]; | ||
597 | struct scb *scb = ascb->scb; | ||
598 | struct control_phy *control_phy = &scb->control_phy; | ||
599 | |||
600 | scb->header.opcode = CONTROL_PHY; | ||
601 | control_phy->phy_id = (u8) phy_id; | ||
602 | control_phy->sub_func = subfunc; | ||
603 | |||
604 | switch (subfunc) { | ||
605 | case EXECUTE_HARD_RESET: /* 0x81 */ | ||
606 | case ENABLE_PHY: /* 0x01 */ | ||
607 | /* decide hot plug delay */ | ||
608 | control_phy->hot_plug_delay = HOTPLUG_DELAY_TIMEOUT; | ||
609 | |||
610 | /* decide speed mask */ | ||
611 | set_speed_mask(&control_phy->speed_mask, phy->phy_desc); | ||
612 | |||
613 | /* initiator port settings are in the hi nibble */ | ||
614 | if (phy->sas_phy.role == PHY_ROLE_INITIATOR) | ||
615 | control_phy->port_type = SAS_PROTO_ALL << 4; | ||
616 | else if (phy->sas_phy.role == PHY_ROLE_TARGET) | ||
617 | control_phy->port_type = SAS_PROTO_ALL; | ||
618 | else | ||
619 | control_phy->port_type = | ||
620 | (SAS_PROTO_ALL << 4) | SAS_PROTO_ALL; | ||
621 | |||
622 | /* link reset retries, this should be nominal */ | ||
623 | control_phy->link_reset_retries = 10; | ||
624 | |||
625 | case RELEASE_SPINUP_HOLD: /* 0x02 */ | ||
626 | /* decide the func_mask */ | ||
627 | control_phy->func_mask = FUNCTION_MASK_DEFAULT; | ||
628 | if (phy->phy_desc->flags & ASD_SATA_SPINUP_HOLD) | ||
629 | control_phy->func_mask &= ~SPINUP_HOLD_DIS; | ||
630 | else | ||
631 | control_phy->func_mask |= SPINUP_HOLD_DIS; | ||
632 | } | ||
633 | |||
634 | control_phy->conn_handle = cpu_to_le16(0xFFFF); | ||
635 | |||
636 | ascb->tasklet_complete = control_phy_tasklet_complete; | ||
637 | } | ||
638 | |||
639 | /* ---------- INITIATE LINK ADM TASK ---------- */ | ||
640 | |||
641 | static void link_adm_tasklet_complete(struct asd_ascb *ascb, | ||
642 | struct done_list_struct *dl) | ||
643 | { | ||
644 | u8 opcode = dl->opcode; | ||
645 | struct initiate_link_adm *link_adm = &ascb->scb->link_adm; | ||
646 | u8 phy_id = link_adm->phy_id; | ||
647 | |||
648 | if (opcode != TC_NO_ERROR) { | ||
649 | asd_printk("phy%d: link adm task 0x%x completed with error " | ||
650 | "0x%x\n", phy_id, link_adm->sub_func, opcode); | ||
651 | } | ||
652 | ASD_DPRINTK("phy%d: link adm task 0x%x: 0x%x\n", | ||
653 | phy_id, link_adm->sub_func, opcode); | ||
654 | |||
655 | asd_ascb_free(ascb); | ||
656 | } | ||
657 | |||
658 | void asd_build_initiate_link_adm_task(struct asd_ascb *ascb, int phy_id, | ||
659 | u8 subfunc) | ||
660 | { | ||
661 | struct scb *scb = ascb->scb; | ||
662 | struct initiate_link_adm *link_adm = &scb->link_adm; | ||
663 | |||
664 | scb->header.opcode = INITIATE_LINK_ADM_TASK; | ||
665 | |||
666 | link_adm->phy_id = phy_id; | ||
667 | link_adm->sub_func = subfunc; | ||
668 | link_adm->conn_handle = cpu_to_le16(0xFFFF); | ||
669 | |||
670 | ascb->tasklet_complete = link_adm_tasklet_complete; | ||
671 | } | ||
672 | |||
673 | /* ---------- SCB timer ---------- */ | ||
674 | |||
675 | /** | ||
676 | * asd_ascb_timedout -- called when a pending SCB's timer has expired | ||
677 | * @data: unsigned long, a pointer to the ascb in question | ||
678 | * | ||
679 | * This is the default timeout function which does the most necessary. | ||
680 | * Upper layers can implement their own timeout function, say to free | ||
681 | * resources they have with this SCB, and then call this one at the | ||
682 | * end of their timeout function. To do this, one should initialize | ||
683 | * the ascb->timer.{function, data, expires} prior to calling the post | ||
684 | * funcion. The timer is started by the post function. | ||
685 | */ | ||
686 | void asd_ascb_timedout(unsigned long data) | ||
687 | { | ||
688 | struct asd_ascb *ascb = (void *) data; | ||
689 | struct asd_seq_data *seq = &ascb->ha->seq; | ||
690 | unsigned long flags; | ||
691 | |||
692 | ASD_DPRINTK("scb:0x%x timed out\n", ascb->scb->header.opcode); | ||
693 | |||
694 | spin_lock_irqsave(&seq->pend_q_lock, flags); | ||
695 | seq->pending--; | ||
696 | list_del_init(&ascb->list); | ||
697 | spin_unlock_irqrestore(&seq->pend_q_lock, flags); | ||
698 | |||
699 | asd_ascb_free(ascb); | ||
700 | } | ||
701 | |||
702 | /* ---------- CONTROL PHY ---------- */ | ||
703 | |||
704 | /* Given the spec value, return a driver value. */ | ||
705 | static const int phy_func_table[] = { | ||
706 | [PHY_FUNC_NOP] = PHY_NO_OP, | ||
707 | [PHY_FUNC_LINK_RESET] = ENABLE_PHY, | ||
708 | [PHY_FUNC_HARD_RESET] = EXECUTE_HARD_RESET, | ||
709 | [PHY_FUNC_DISABLE] = DISABLE_PHY, | ||
710 | [PHY_FUNC_RELEASE_SPINUP_HOLD] = RELEASE_SPINUP_HOLD, | ||
711 | }; | ||
712 | |||
713 | int asd_control_phy(struct asd_sas_phy *phy, enum phy_func func) | ||
714 | { | ||
715 | struct asd_ha_struct *asd_ha = phy->ha->lldd_ha; | ||
716 | struct asd_ascb *ascb; | ||
717 | int res = 1; | ||
718 | |||
719 | if (func == PHY_FUNC_CLEAR_ERROR_LOG) | ||
720 | return -ENOSYS; | ||
721 | |||
722 | ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL); | ||
723 | if (!ascb) | ||
724 | return -ENOMEM; | ||
725 | |||
726 | asd_build_control_phy(ascb, phy->id, phy_func_table[func]); | ||
727 | res = asd_post_ascb_list(asd_ha, ascb , 1); | ||
728 | if (res) | ||
729 | asd_ascb_free(ascb); | ||
730 | |||
731 | return res; | ||
732 | } | ||
diff --git a/drivers/scsi/aic94xx/aic94xx_sds.c b/drivers/scsi/aic94xx/aic94xx_sds.c new file mode 100644 index 000000000000..eec1e0db0e0f --- /dev/null +++ b/drivers/scsi/aic94xx/aic94xx_sds.c | |||
@@ -0,0 +1,1136 @@ | |||
1 | /* | ||
2 | * Aic94xx SAS/SATA driver access to shared data structures and memory | ||
3 | * maps. | ||
4 | * | ||
5 | * Copyright (C) 2005 Adaptec, Inc. All rights reserved. | ||
6 | * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> | ||
7 | * | ||
8 | * This file is licensed under GPLv2. | ||
9 | * | ||
10 | * This file is part of the aic94xx driver. | ||
11 | * | ||
12 | * The aic94xx driver is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License as | ||
14 | * published by the Free Software Foundation; version 2 of the | ||
15 | * License. | ||
16 | * | ||
17 | * The aic94xx driver is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
20 | * General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with the aic94xx driver; if not, write to the Free Software | ||
24 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
25 | * | ||
26 | */ | ||
27 | |||
28 | #include <linux/pci.h> | ||
29 | #include <linux/delay.h> | ||
30 | |||
31 | #include "aic94xx.h" | ||
32 | #include "aic94xx_reg.h" | ||
33 | |||
34 | /* ---------- OCM stuff ---------- */ | ||
35 | |||
36 | struct asd_ocm_dir_ent { | ||
37 | u8 type; | ||
38 | u8 offs[3]; | ||
39 | u8 _r1; | ||
40 | u8 size[3]; | ||
41 | } __attribute__ ((packed)); | ||
42 | |||
43 | struct asd_ocm_dir { | ||
44 | char sig[2]; | ||
45 | u8 _r1[2]; | ||
46 | u8 major; /* 0 */ | ||
47 | u8 minor; /* 0 */ | ||
48 | u8 _r2; | ||
49 | u8 num_de; | ||
50 | struct asd_ocm_dir_ent entry[15]; | ||
51 | } __attribute__ ((packed)); | ||
52 | |||
53 | #define OCM_DE_OCM_DIR 0x00 | ||
54 | #define OCM_DE_WIN_DRVR 0x01 | ||
55 | #define OCM_DE_BIOS_CHIM 0x02 | ||
56 | #define OCM_DE_RAID_ENGN 0x03 | ||
57 | #define OCM_DE_BIOS_INTL 0x04 | ||
58 | #define OCM_DE_BIOS_CHIM_OSM 0x05 | ||
59 | #define OCM_DE_BIOS_CHIM_DYNAMIC 0x06 | ||
60 | #define OCM_DE_ADDC2C_RES0 0x07 | ||
61 | #define OCM_DE_ADDC2C_RES1 0x08 | ||
62 | #define OCM_DE_ADDC2C_RES2 0x09 | ||
63 | #define OCM_DE_ADDC2C_RES3 0x0A | ||
64 | |||
65 | #define OCM_INIT_DIR_ENTRIES 5 | ||
66 | /*************************************************************************** | ||
67 | * OCM dircetory default | ||
68 | ***************************************************************************/ | ||
69 | static struct asd_ocm_dir OCMDirInit = | ||
70 | { | ||
71 | .sig = {0x4D, 0x4F}, /* signature */ | ||
72 | .num_de = OCM_INIT_DIR_ENTRIES, /* no. of directory entries */ | ||
73 | }; | ||
74 | |||
75 | /*************************************************************************** | ||
76 | * OCM dircetory Entries default | ||
77 | ***************************************************************************/ | ||
78 | static struct asd_ocm_dir_ent OCMDirEntriesInit[OCM_INIT_DIR_ENTRIES] = | ||
79 | { | ||
80 | { | ||
81 | .type = (OCM_DE_ADDC2C_RES0), /* Entry type */ | ||
82 | .offs = {128}, /* Offset */ | ||
83 | .size = {0, 4}, /* size */ | ||
84 | }, | ||
85 | { | ||
86 | .type = (OCM_DE_ADDC2C_RES1), /* Entry type */ | ||
87 | .offs = {128, 4}, /* Offset */ | ||
88 | .size = {0, 4}, /* size */ | ||
89 | }, | ||
90 | { | ||
91 | .type = (OCM_DE_ADDC2C_RES2), /* Entry type */ | ||
92 | .offs = {128, 8}, /* Offset */ | ||
93 | .size = {0, 4}, /* size */ | ||
94 | }, | ||
95 | { | ||
96 | .type = (OCM_DE_ADDC2C_RES3), /* Entry type */ | ||
97 | .offs = {128, 12}, /* Offset */ | ||
98 | .size = {0, 4}, /* size */ | ||
99 | }, | ||
100 | { | ||
101 | .type = (OCM_DE_WIN_DRVR), /* Entry type */ | ||
102 | .offs = {128, 16}, /* Offset */ | ||
103 | .size = {128, 235, 1}, /* size */ | ||
104 | }, | ||
105 | }; | ||
106 | |||
107 | struct asd_bios_chim_struct { | ||
108 | char sig[4]; | ||
109 | u8 major; /* 1 */ | ||
110 | u8 minor; /* 0 */ | ||
111 | u8 bios_major; | ||
112 | u8 bios_minor; | ||
113 | __le32 bios_build; | ||
114 | u8 flags; | ||
115 | u8 pci_slot; | ||
116 | __le16 ue_num; | ||
117 | __le16 ue_size; | ||
118 | u8 _r[14]; | ||
119 | /* The unit element array is right here. | ||
120 | */ | ||
121 | } __attribute__ ((packed)); | ||
122 | |||
123 | /** | ||
124 | * asd_read_ocm_seg - read an on chip memory (OCM) segment | ||
125 | * @asd_ha: pointer to the host adapter structure | ||
126 | * @buffer: where to write the read data | ||
127 | * @offs: offset into OCM where to read from | ||
128 | * @size: how many bytes to read | ||
129 | * | ||
130 | * Return the number of bytes not read. Return 0 on success. | ||
131 | */ | ||
132 | static int asd_read_ocm_seg(struct asd_ha_struct *asd_ha, void *buffer, | ||
133 | u32 offs, int size) | ||
134 | { | ||
135 | u8 *p = buffer; | ||
136 | if (unlikely(asd_ha->iospace)) | ||
137 | asd_read_reg_string(asd_ha, buffer, offs+OCM_BASE_ADDR, size); | ||
138 | else { | ||
139 | for ( ; size > 0; size--, offs++, p++) | ||
140 | *p = asd_read_ocm_byte(asd_ha, offs); | ||
141 | } | ||
142 | return size; | ||
143 | } | ||
144 | |||
145 | static int asd_read_ocm_dir(struct asd_ha_struct *asd_ha, | ||
146 | struct asd_ocm_dir *dir, u32 offs) | ||
147 | { | ||
148 | int err = asd_read_ocm_seg(asd_ha, dir, offs, sizeof(*dir)); | ||
149 | if (err) { | ||
150 | ASD_DPRINTK("couldn't read ocm segment\n"); | ||
151 | return err; | ||
152 | } | ||
153 | |||
154 | if (dir->sig[0] != 'M' || dir->sig[1] != 'O') { | ||
155 | ASD_DPRINTK("no valid dir signature(%c%c) at start of OCM\n", | ||
156 | dir->sig[0], dir->sig[1]); | ||
157 | return -ENOENT; | ||
158 | } | ||
159 | if (dir->major != 0) { | ||
160 | asd_printk("unsupported major version of ocm dir:0x%x\n", | ||
161 | dir->major); | ||
162 | return -ENOENT; | ||
163 | } | ||
164 | dir->num_de &= 0xf; | ||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | /** | ||
169 | * asd_write_ocm_seg - write an on chip memory (OCM) segment | ||
170 | * @asd_ha: pointer to the host adapter structure | ||
171 | * @buffer: where to read the write data | ||
172 | * @offs: offset into OCM to write to | ||
173 | * @size: how many bytes to write | ||
174 | * | ||
175 | * Return the number of bytes not written. Return 0 on success. | ||
176 | */ | ||
177 | static void asd_write_ocm_seg(struct asd_ha_struct *asd_ha, void *buffer, | ||
178 | u32 offs, int size) | ||
179 | { | ||
180 | u8 *p = buffer; | ||
181 | if (unlikely(asd_ha->iospace)) | ||
182 | asd_write_reg_string(asd_ha, buffer, offs+OCM_BASE_ADDR, size); | ||
183 | else { | ||
184 | for ( ; size > 0; size--, offs++, p++) | ||
185 | asd_write_ocm_byte(asd_ha, offs, *p); | ||
186 | } | ||
187 | return; | ||
188 | } | ||
189 | |||
190 | #define THREE_TO_NUM(X) ((X)[0] | ((X)[1] << 8) | ((X)[2] << 16)) | ||
191 | |||
192 | static int asd_find_dir_entry(struct asd_ocm_dir *dir, u8 type, | ||
193 | u32 *offs, u32 *size) | ||
194 | { | ||
195 | int i; | ||
196 | struct asd_ocm_dir_ent *ent; | ||
197 | |||
198 | for (i = 0; i < dir->num_de; i++) { | ||
199 | if (dir->entry[i].type == type) | ||
200 | break; | ||
201 | } | ||
202 | if (i >= dir->num_de) | ||
203 | return -ENOENT; | ||
204 | ent = &dir->entry[i]; | ||
205 | *offs = (u32) THREE_TO_NUM(ent->offs); | ||
206 | *size = (u32) THREE_TO_NUM(ent->size); | ||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | #define OCM_BIOS_CHIM_DE 2 | ||
211 | #define BC_BIOS_PRESENT 1 | ||
212 | |||
213 | static int asd_get_bios_chim(struct asd_ha_struct *asd_ha, | ||
214 | struct asd_ocm_dir *dir) | ||
215 | { | ||
216 | int err; | ||
217 | struct asd_bios_chim_struct *bc_struct; | ||
218 | u32 offs, size; | ||
219 | |||
220 | err = asd_find_dir_entry(dir, OCM_BIOS_CHIM_DE, &offs, &size); | ||
221 | if (err) { | ||
222 | ASD_DPRINTK("couldn't find BIOS_CHIM dir ent\n"); | ||
223 | goto out; | ||
224 | } | ||
225 | err = -ENOMEM; | ||
226 | bc_struct = kmalloc(sizeof(*bc_struct), GFP_KERNEL); | ||
227 | if (!bc_struct) { | ||
228 | asd_printk("no memory for bios_chim struct\n"); | ||
229 | goto out; | ||
230 | } | ||
231 | err = asd_read_ocm_seg(asd_ha, (void *)bc_struct, offs, | ||
232 | sizeof(*bc_struct)); | ||
233 | if (err) { | ||
234 | ASD_DPRINTK("couldn't read ocm segment\n"); | ||
235 | goto out2; | ||
236 | } | ||
237 | if (strncmp(bc_struct->sig, "SOIB", 4) | ||
238 | && strncmp(bc_struct->sig, "IPSA", 4)) { | ||
239 | ASD_DPRINTK("BIOS_CHIM entry has no valid sig(%c%c%c%c)\n", | ||
240 | bc_struct->sig[0], bc_struct->sig[1], | ||
241 | bc_struct->sig[2], bc_struct->sig[3]); | ||
242 | err = -ENOENT; | ||
243 | goto out2; | ||
244 | } | ||
245 | if (bc_struct->major != 1) { | ||
246 | asd_printk("BIOS_CHIM unsupported major version:0x%x\n", | ||
247 | bc_struct->major); | ||
248 | err = -ENOENT; | ||
249 | goto out2; | ||
250 | } | ||
251 | if (bc_struct->flags & BC_BIOS_PRESENT) { | ||
252 | asd_ha->hw_prof.bios.present = 1; | ||
253 | asd_ha->hw_prof.bios.maj = bc_struct->bios_major; | ||
254 | asd_ha->hw_prof.bios.min = bc_struct->bios_minor; | ||
255 | asd_ha->hw_prof.bios.bld = le32_to_cpu(bc_struct->bios_build); | ||
256 | ASD_DPRINTK("BIOS present (%d,%d), %d\n", | ||
257 | asd_ha->hw_prof.bios.maj, | ||
258 | asd_ha->hw_prof.bios.min, | ||
259 | asd_ha->hw_prof.bios.bld); | ||
260 | } | ||
261 | asd_ha->hw_prof.ue.num = le16_to_cpu(bc_struct->ue_num); | ||
262 | asd_ha->hw_prof.ue.size= le16_to_cpu(bc_struct->ue_size); | ||
263 | ASD_DPRINTK("ue num:%d, ue size:%d\n", asd_ha->hw_prof.ue.num, | ||
264 | asd_ha->hw_prof.ue.size); | ||
265 | size = asd_ha->hw_prof.ue.num * asd_ha->hw_prof.ue.size; | ||
266 | if (size > 0) { | ||
267 | err = -ENOMEM; | ||
268 | asd_ha->hw_prof.ue.area = kmalloc(size, GFP_KERNEL); | ||
269 | if (!asd_ha->hw_prof.ue.area) | ||
270 | goto out2; | ||
271 | err = asd_read_ocm_seg(asd_ha, (void *)asd_ha->hw_prof.ue.area, | ||
272 | offs + sizeof(*bc_struct), size); | ||
273 | if (err) { | ||
274 | kfree(asd_ha->hw_prof.ue.area); | ||
275 | asd_ha->hw_prof.ue.area = NULL; | ||
276 | asd_ha->hw_prof.ue.num = 0; | ||
277 | asd_ha->hw_prof.ue.size = 0; | ||
278 | ASD_DPRINTK("couldn't read ue entries(%d)\n", err); | ||
279 | } | ||
280 | } | ||
281 | out2: | ||
282 | kfree(bc_struct); | ||
283 | out: | ||
284 | return err; | ||
285 | } | ||
286 | |||
287 | static void | ||
288 | asd_hwi_initialize_ocm_dir (struct asd_ha_struct *asd_ha) | ||
289 | { | ||
290 | int i; | ||
291 | |||
292 | /* Zero OCM */ | ||
293 | for (i = 0; i < OCM_MAX_SIZE; i += 4) | ||
294 | asd_write_ocm_dword(asd_ha, i, 0); | ||
295 | |||
296 | /* Write Dir */ | ||
297 | asd_write_ocm_seg(asd_ha, &OCMDirInit, 0, | ||
298 | sizeof(struct asd_ocm_dir)); | ||
299 | |||
300 | /* Write Dir Entries */ | ||
301 | for (i = 0; i < OCM_INIT_DIR_ENTRIES; i++) | ||
302 | asd_write_ocm_seg(asd_ha, &OCMDirEntriesInit[i], | ||
303 | sizeof(struct asd_ocm_dir) + | ||
304 | (i * sizeof(struct asd_ocm_dir_ent)) | ||
305 | , sizeof(struct asd_ocm_dir_ent)); | ||
306 | |||
307 | } | ||
308 | |||
309 | static int | ||
310 | asd_hwi_check_ocm_access (struct asd_ha_struct *asd_ha) | ||
311 | { | ||
312 | struct pci_dev *pcidev = asd_ha->pcidev; | ||
313 | u32 reg; | ||
314 | int err = 0; | ||
315 | u32 v; | ||
316 | |||
317 | /* check if OCM has been initialized by BIOS */ | ||
318 | reg = asd_read_reg_dword(asd_ha, EXSICNFGR); | ||
319 | |||
320 | if (!(reg & OCMINITIALIZED)) { | ||
321 | err = pci_read_config_dword(pcidev, PCIC_INTRPT_STAT, &v); | ||
322 | if (err) { | ||
323 | asd_printk("couldn't access PCIC_INTRPT_STAT of %s\n", | ||
324 | pci_name(pcidev)); | ||
325 | goto out; | ||
326 | } | ||
327 | |||
328 | printk(KERN_INFO "OCM is not initialized by BIOS," | ||
329 | "reinitialize it and ignore it, current IntrptStatus" | ||
330 | "is 0x%x\n", v); | ||
331 | |||
332 | if (v) | ||
333 | err = pci_write_config_dword(pcidev, | ||
334 | PCIC_INTRPT_STAT, v); | ||
335 | if (err) { | ||
336 | asd_printk("couldn't write PCIC_INTRPT_STAT of %s\n", | ||
337 | pci_name(pcidev)); | ||
338 | goto out; | ||
339 | } | ||
340 | |||
341 | asd_hwi_initialize_ocm_dir(asd_ha); | ||
342 | |||
343 | } | ||
344 | out: | ||
345 | return err; | ||
346 | } | ||
347 | |||
348 | /** | ||
349 | * asd_read_ocm - read on chip memory (OCM) | ||
350 | * @asd_ha: pointer to the host adapter structure | ||
351 | */ | ||
352 | int asd_read_ocm(struct asd_ha_struct *asd_ha) | ||
353 | { | ||
354 | int err; | ||
355 | struct asd_ocm_dir *dir; | ||
356 | |||
357 | if (asd_hwi_check_ocm_access(asd_ha)) | ||
358 | return -1; | ||
359 | |||
360 | dir = kmalloc(sizeof(*dir), GFP_KERNEL); | ||
361 | if (!dir) { | ||
362 | asd_printk("no memory for ocm dir\n"); | ||
363 | return -ENOMEM; | ||
364 | } | ||
365 | |||
366 | err = asd_read_ocm_dir(asd_ha, dir, 0); | ||
367 | if (err) | ||
368 | goto out; | ||
369 | |||
370 | err = asd_get_bios_chim(asd_ha, dir); | ||
371 | out: | ||
372 | kfree(dir); | ||
373 | return err; | ||
374 | } | ||
375 | |||
376 | /* ---------- FLASH stuff ---------- */ | ||
377 | |||
378 | #define FLASH_RESET 0xF0 | ||
379 | #define FLASH_MANUF_AMD 1 | ||
380 | |||
381 | #define FLASH_SIZE 0x200000 | ||
382 | #define FLASH_DIR_COOKIE "*** ADAPTEC FLASH DIRECTORY *** " | ||
383 | #define FLASH_NEXT_ENTRY_OFFS 0x2000 | ||
384 | #define FLASH_MAX_DIR_ENTRIES 32 | ||
385 | |||
386 | #define FLASH_DE_TYPE_MASK 0x3FFFFFFF | ||
387 | #define FLASH_DE_MS 0x120 | ||
388 | #define FLASH_DE_CTRL_A_USER 0xE0 | ||
389 | |||
390 | struct asd_flash_de { | ||
391 | __le32 type; | ||
392 | __le32 offs; | ||
393 | __le32 pad_size; | ||
394 | __le32 image_size; | ||
395 | __le32 chksum; | ||
396 | u8 _r[12]; | ||
397 | u8 version[32]; | ||
398 | } __attribute__ ((packed)); | ||
399 | |||
400 | struct asd_flash_dir { | ||
401 | u8 cookie[32]; | ||
402 | __le32 rev; /* 2 */ | ||
403 | __le32 chksum; | ||
404 | __le32 chksum_antidote; | ||
405 | __le32 bld; | ||
406 | u8 bld_id[32]; /* build id data */ | ||
407 | u8 ver_data[32]; /* date and time of build */ | ||
408 | __le32 ae_mask; | ||
409 | __le32 v_mask; | ||
410 | __le32 oc_mask; | ||
411 | u8 _r[20]; | ||
412 | struct asd_flash_de dir_entry[FLASH_MAX_DIR_ENTRIES]; | ||
413 | } __attribute__ ((packed)); | ||
414 | |||
415 | struct asd_manuf_sec { | ||
416 | char sig[2]; /* 'S', 'M' */ | ||
417 | u16 offs_next; | ||
418 | u8 maj; /* 0 */ | ||
419 | u8 min; /* 0 */ | ||
420 | u16 chksum; | ||
421 | u16 size; | ||
422 | u8 _r[6]; | ||
423 | u8 sas_addr[SAS_ADDR_SIZE]; | ||
424 | u8 pcba_sn[ASD_PCBA_SN_SIZE]; | ||
425 | /* Here start the other segments */ | ||
426 | u8 linked_list[0]; | ||
427 | } __attribute__ ((packed)); | ||
428 | |||
429 | struct asd_manuf_phy_desc { | ||
430 | u8 state; /* low 4 bits */ | ||
431 | #define MS_PHY_STATE_ENABLEABLE 0 | ||
432 | #define MS_PHY_STATE_REPORTED 1 | ||
433 | #define MS_PHY_STATE_HIDDEN 2 | ||
434 | u8 phy_id; | ||
435 | u16 _r; | ||
436 | u8 phy_control_0; /* mode 5 reg 0x160 */ | ||
437 | u8 phy_control_1; /* mode 5 reg 0x161 */ | ||
438 | u8 phy_control_2; /* mode 5 reg 0x162 */ | ||
439 | u8 phy_control_3; /* mode 5 reg 0x163 */ | ||
440 | } __attribute__ ((packed)); | ||
441 | |||
442 | struct asd_manuf_phy_param { | ||
443 | char sig[2]; /* 'P', 'M' */ | ||
444 | u16 next; | ||
445 | u8 maj; /* 0 */ | ||
446 | u8 min; /* 2 */ | ||
447 | u8 num_phy_desc; /* 8 */ | ||
448 | u8 phy_desc_size; /* 8 */ | ||
449 | u8 _r[3]; | ||
450 | u8 usage_model_id; | ||
451 | u32 _r2; | ||
452 | struct asd_manuf_phy_desc phy_desc[ASD_MAX_PHYS]; | ||
453 | } __attribute__ ((packed)); | ||
454 | |||
455 | #if 0 | ||
456 | static const char *asd_sb_type[] = { | ||
457 | "unknown", | ||
458 | "SGPIO", | ||
459 | [2 ... 0x7F] = "unknown", | ||
460 | [0x80] = "ADPT_I2C", | ||
461 | [0x81 ... 0xFF] = "VENDOR_UNIQUExx" | ||
462 | }; | ||
463 | #endif | ||
464 | |||
465 | struct asd_ms_sb_desc { | ||
466 | u8 type; | ||
467 | u8 node_desc_index; | ||
468 | u8 conn_desc_index; | ||
469 | u8 _recvd[0]; | ||
470 | } __attribute__ ((packed)); | ||
471 | |||
472 | #if 0 | ||
473 | static const char *asd_conn_type[] = { | ||
474 | [0 ... 7] = "unknown", | ||
475 | "SFF8470", | ||
476 | "SFF8482", | ||
477 | "SFF8484", | ||
478 | [0x80] = "PCIX_DAUGHTER0", | ||
479 | [0x81] = "SAS_DAUGHTER0", | ||
480 | [0x82 ... 0xFF] = "VENDOR_UNIQUExx" | ||
481 | }; | ||
482 | |||
483 | static const char *asd_conn_location[] = { | ||
484 | "unknown", | ||
485 | "internal", | ||
486 | "external", | ||
487 | "board_to_board", | ||
488 | }; | ||
489 | #endif | ||
490 | |||
491 | struct asd_ms_conn_desc { | ||
492 | u8 type; | ||
493 | u8 location; | ||
494 | u8 num_sideband_desc; | ||
495 | u8 size_sideband_desc; | ||
496 | u32 _resvd; | ||
497 | u8 name[16]; | ||
498 | struct asd_ms_sb_desc sb_desc[0]; | ||
499 | } __attribute__ ((packed)); | ||
500 | |||
501 | struct asd_nd_phy_desc { | ||
502 | u8 vp_attch_type; | ||
503 | u8 attch_specific[0]; | ||
504 | } __attribute__ ((packed)); | ||
505 | |||
506 | #if 0 | ||
507 | static const char *asd_node_type[] = { | ||
508 | "IOP", | ||
509 | "IO_CONTROLLER", | ||
510 | "EXPANDER", | ||
511 | "PORT_MULTIPLIER", | ||
512 | "PORT_MULTIPLEXER", | ||
513 | "MULTI_DROP_I2C_BUS", | ||
514 | }; | ||
515 | #endif | ||
516 | |||
517 | struct asd_ms_node_desc { | ||
518 | u8 type; | ||
519 | u8 num_phy_desc; | ||
520 | u8 size_phy_desc; | ||
521 | u8 _resvd; | ||
522 | u8 name[16]; | ||
523 | struct asd_nd_phy_desc phy_desc[0]; | ||
524 | } __attribute__ ((packed)); | ||
525 | |||
526 | struct asd_ms_conn_map { | ||
527 | char sig[2]; /* 'M', 'C' */ | ||
528 | __le16 next; | ||
529 | u8 maj; /* 0 */ | ||
530 | u8 min; /* 0 */ | ||
531 | __le16 cm_size; /* size of this struct */ | ||
532 | u8 num_conn; | ||
533 | u8 conn_size; | ||
534 | u8 num_nodes; | ||
535 | u8 usage_model_id; | ||
536 | u32 _resvd; | ||
537 | struct asd_ms_conn_desc conn_desc[0]; | ||
538 | struct asd_ms_node_desc node_desc[0]; | ||
539 | } __attribute__ ((packed)); | ||
540 | |||
541 | struct asd_ctrla_phy_entry { | ||
542 | u8 sas_addr[SAS_ADDR_SIZE]; | ||
543 | u8 sas_link_rates; /* max in hi bits, min in low bits */ | ||
544 | u8 flags; | ||
545 | u8 sata_link_rates; | ||
546 | u8 _r[5]; | ||
547 | } __attribute__ ((packed)); | ||
548 | |||
549 | struct asd_ctrla_phy_settings { | ||
550 | u8 id0; /* P'h'y */ | ||
551 | u8 _r; | ||
552 | u16 next; | ||
553 | u8 num_phys; /* number of PHYs in the PCI function */ | ||
554 | u8 _r2[3]; | ||
555 | struct asd_ctrla_phy_entry phy_ent[ASD_MAX_PHYS]; | ||
556 | } __attribute__ ((packed)); | ||
557 | |||
558 | struct asd_ll_el { | ||
559 | u8 id0; | ||
560 | u8 id1; | ||
561 | __le16 next; | ||
562 | u8 something_here[0]; | ||
563 | } __attribute__ ((packed)); | ||
564 | |||
565 | static int asd_poll_flash(struct asd_ha_struct *asd_ha) | ||
566 | { | ||
567 | int c; | ||
568 | u8 d; | ||
569 | |||
570 | for (c = 5000; c > 0; c--) { | ||
571 | d = asd_read_reg_byte(asd_ha, asd_ha->hw_prof.flash.bar); | ||
572 | d ^= asd_read_reg_byte(asd_ha, asd_ha->hw_prof.flash.bar); | ||
573 | if (!d) | ||
574 | return 0; | ||
575 | udelay(5); | ||
576 | } | ||
577 | return -ENOENT; | ||
578 | } | ||
579 | |||
580 | static int asd_reset_flash(struct asd_ha_struct *asd_ha) | ||
581 | { | ||
582 | int err; | ||
583 | |||
584 | err = asd_poll_flash(asd_ha); | ||
585 | if (err) | ||
586 | return err; | ||
587 | asd_write_reg_byte(asd_ha, asd_ha->hw_prof.flash.bar, FLASH_RESET); | ||
588 | err = asd_poll_flash(asd_ha); | ||
589 | |||
590 | return err; | ||
591 | } | ||
592 | |||
593 | static inline int asd_read_flash_seg(struct asd_ha_struct *asd_ha, | ||
594 | void *buffer, u32 offs, int size) | ||
595 | { | ||
596 | asd_read_reg_string(asd_ha, buffer, asd_ha->hw_prof.flash.bar+offs, | ||
597 | size); | ||
598 | return 0; | ||
599 | } | ||
600 | |||
601 | /** | ||
602 | * asd_find_flash_dir - finds and reads the flash directory | ||
603 | * @asd_ha: pointer to the host adapter structure | ||
604 | * @flash_dir: pointer to flash directory structure | ||
605 | * | ||
606 | * If found, the flash directory segment will be copied to | ||
607 | * @flash_dir. Return 1 if found, 0 if not. | ||
608 | */ | ||
609 | static int asd_find_flash_dir(struct asd_ha_struct *asd_ha, | ||
610 | struct asd_flash_dir *flash_dir) | ||
611 | { | ||
612 | u32 v; | ||
613 | for (v = 0; v < FLASH_SIZE; v += FLASH_NEXT_ENTRY_OFFS) { | ||
614 | asd_read_flash_seg(asd_ha, flash_dir, v, | ||
615 | sizeof(FLASH_DIR_COOKIE)-1); | ||
616 | if (memcmp(flash_dir->cookie, FLASH_DIR_COOKIE, | ||
617 | sizeof(FLASH_DIR_COOKIE)-1) == 0) { | ||
618 | asd_ha->hw_prof.flash.dir_offs = v; | ||
619 | asd_read_flash_seg(asd_ha, flash_dir, v, | ||
620 | sizeof(*flash_dir)); | ||
621 | return 1; | ||
622 | } | ||
623 | } | ||
624 | return 0; | ||
625 | } | ||
626 | |||
627 | static int asd_flash_getid(struct asd_ha_struct *asd_ha) | ||
628 | { | ||
629 | int err = 0; | ||
630 | u32 reg, inc; | ||
631 | |||
632 | reg = asd_read_reg_dword(asd_ha, EXSICNFGR); | ||
633 | |||
634 | if (!(reg & FLASHEX)) { | ||
635 | ASD_DPRINTK("flash doesn't exist\n"); | ||
636 | return -ENOENT; | ||
637 | } | ||
638 | if (pci_read_config_dword(asd_ha->pcidev, PCI_CONF_FLSH_BAR, | ||
639 | &asd_ha->hw_prof.flash.bar)) { | ||
640 | asd_printk("couldn't read PCI_CONF_FLSH_BAR of %s\n", | ||
641 | pci_name(asd_ha->pcidev)); | ||
642 | return -ENOENT; | ||
643 | } | ||
644 | asd_ha->hw_prof.flash.present = 1; | ||
645 | asd_ha->hw_prof.flash.wide = reg & FLASHW ? 1 : 0; | ||
646 | err = asd_reset_flash(asd_ha); | ||
647 | if (err) { | ||
648 | ASD_DPRINTK("couldn't reset flash(%d)\n", err); | ||
649 | return err; | ||
650 | } | ||
651 | /* Get flash info. This would most likely be AMD Am29LV family flash. | ||
652 | * First try the sequence for word mode. It is the same as for | ||
653 | * 008B (byte mode only), 160B (word mode) and 800D (word mode). | ||
654 | */ | ||
655 | reg = asd_ha->hw_prof.flash.bar; | ||
656 | inc = asd_ha->hw_prof.flash.wide ? 2 : 1; | ||
657 | asd_write_reg_byte(asd_ha, reg + 0x555, 0xAA); | ||
658 | asd_write_reg_byte(asd_ha, reg + 0x2AA, 0x55); | ||
659 | asd_write_reg_byte(asd_ha, reg + 0x555, 0x90); | ||
660 | asd_ha->hw_prof.flash.manuf = asd_read_reg_byte(asd_ha, reg); | ||
661 | asd_ha->hw_prof.flash.dev_id= asd_read_reg_byte(asd_ha,reg+inc); | ||
662 | asd_ha->hw_prof.flash.sec_prot = asd_read_reg_byte(asd_ha,reg+inc+inc); | ||
663 | /* Get out of autoselect mode. */ | ||
664 | err = asd_reset_flash(asd_ha); | ||
665 | |||
666 | if (asd_ha->hw_prof.flash.manuf == FLASH_MANUF_AMD) { | ||
667 | ASD_DPRINTK("0Found FLASH(%d) manuf:%d, dev_id:0x%x, " | ||
668 | "sec_prot:%d\n", | ||
669 | asd_ha->hw_prof.flash.wide ? 16 : 8, | ||
670 | asd_ha->hw_prof.flash.manuf, | ||
671 | asd_ha->hw_prof.flash.dev_id, | ||
672 | asd_ha->hw_prof.flash.sec_prot); | ||
673 | return 0; | ||
674 | } | ||
675 | |||
676 | /* Ok, try the sequence for byte mode of 160B and 800D. | ||
677 | * We may actually never need this. | ||
678 | */ | ||
679 | asd_write_reg_byte(asd_ha, reg + 0xAAA, 0xAA); | ||
680 | asd_write_reg_byte(asd_ha, reg + 0x555, 0x55); | ||
681 | asd_write_reg_byte(asd_ha, reg + 0xAAA, 0x90); | ||
682 | asd_ha->hw_prof.flash.manuf = asd_read_reg_byte(asd_ha, reg); | ||
683 | asd_ha->hw_prof.flash.dev_id = asd_read_reg_byte(asd_ha, reg + 2); | ||
684 | asd_ha->hw_prof.flash.sec_prot = asd_read_reg_byte(asd_ha, reg + 4); | ||
685 | err = asd_reset_flash(asd_ha); | ||
686 | |||
687 | if (asd_ha->hw_prof.flash.manuf == FLASH_MANUF_AMD) { | ||
688 | ASD_DPRINTK("1Found FLASH(%d) manuf:%d, dev_id:0x%x, " | ||
689 | "sec_prot:%d\n", | ||
690 | asd_ha->hw_prof.flash.wide ? 16 : 8, | ||
691 | asd_ha->hw_prof.flash.manuf, | ||
692 | asd_ha->hw_prof.flash.dev_id, | ||
693 | asd_ha->hw_prof.flash.sec_prot); | ||
694 | return 0; | ||
695 | } | ||
696 | |||
697 | return -ENOENT; | ||
698 | } | ||
699 | |||
700 | static u16 asd_calc_flash_chksum(u16 *p, int size) | ||
701 | { | ||
702 | u16 chksum = 0; | ||
703 | |||
704 | while (size-- > 0) | ||
705 | chksum += *p++; | ||
706 | |||
707 | return chksum; | ||
708 | } | ||
709 | |||
710 | |||
711 | static int asd_find_flash_de(struct asd_flash_dir *flash_dir, u32 entry_type, | ||
712 | u32 *offs, u32 *size) | ||
713 | { | ||
714 | int i; | ||
715 | struct asd_flash_de *de; | ||
716 | |||
717 | for (i = 0; i < FLASH_MAX_DIR_ENTRIES; i++) { | ||
718 | u32 type = le32_to_cpu(flash_dir->dir_entry[i].type); | ||
719 | |||
720 | type &= FLASH_DE_TYPE_MASK; | ||
721 | if (type == entry_type) | ||
722 | break; | ||
723 | } | ||
724 | if (i >= FLASH_MAX_DIR_ENTRIES) | ||
725 | return -ENOENT; | ||
726 | de = &flash_dir->dir_entry[i]; | ||
727 | *offs = le32_to_cpu(de->offs); | ||
728 | *size = le32_to_cpu(de->pad_size); | ||
729 | return 0; | ||
730 | } | ||
731 | |||
732 | static int asd_validate_ms(struct asd_manuf_sec *ms) | ||
733 | { | ||
734 | if (ms->sig[0] != 'S' || ms->sig[1] != 'M') { | ||
735 | ASD_DPRINTK("manuf sec: no valid sig(%c%c)\n", | ||
736 | ms->sig[0], ms->sig[1]); | ||
737 | return -ENOENT; | ||
738 | } | ||
739 | if (ms->maj != 0) { | ||
740 | asd_printk("unsupported manuf. sector. major version:%x\n", | ||
741 | ms->maj); | ||
742 | return -ENOENT; | ||
743 | } | ||
744 | ms->offs_next = le16_to_cpu((__force __le16) ms->offs_next); | ||
745 | ms->chksum = le16_to_cpu((__force __le16) ms->chksum); | ||
746 | ms->size = le16_to_cpu((__force __le16) ms->size); | ||
747 | |||
748 | if (asd_calc_flash_chksum((u16 *)ms, ms->size/2)) { | ||
749 | asd_printk("failed manuf sector checksum\n"); | ||
750 | } | ||
751 | |||
752 | return 0; | ||
753 | } | ||
754 | |||
755 | static int asd_ms_get_sas_addr(struct asd_ha_struct *asd_ha, | ||
756 | struct asd_manuf_sec *ms) | ||
757 | { | ||
758 | memcpy(asd_ha->hw_prof.sas_addr, ms->sas_addr, SAS_ADDR_SIZE); | ||
759 | return 0; | ||
760 | } | ||
761 | |||
762 | static int asd_ms_get_pcba_sn(struct asd_ha_struct *asd_ha, | ||
763 | struct asd_manuf_sec *ms) | ||
764 | { | ||
765 | memcpy(asd_ha->hw_prof.pcba_sn, ms->pcba_sn, ASD_PCBA_SN_SIZE); | ||
766 | asd_ha->hw_prof.pcba_sn[ASD_PCBA_SN_SIZE] = '\0'; | ||
767 | return 0; | ||
768 | } | ||
769 | |||
770 | /** | ||
771 | * asd_find_ll_by_id - find a linked list entry by its id | ||
772 | * @start: void pointer to the first element in the linked list | ||
773 | * @id0: the first byte of the id (offs 0) | ||
774 | * @id1: the second byte of the id (offs 1) | ||
775 | * | ||
776 | * @start has to be the _base_ element start, since the | ||
777 | * linked list entries's offset is from this pointer. | ||
778 | * Some linked list entries use only the first id, in which case | ||
779 | * you can pass 0xFF for the second. | ||
780 | */ | ||
781 | static void *asd_find_ll_by_id(void * const start, const u8 id0, const u8 id1) | ||
782 | { | ||
783 | struct asd_ll_el *el = start; | ||
784 | |||
785 | do { | ||
786 | switch (id1) { | ||
787 | default: | ||
788 | if (el->id1 == id1) | ||
789 | case 0xFF: | ||
790 | if (el->id0 == id0) | ||
791 | return el; | ||
792 | } | ||
793 | el = start + le16_to_cpu(el->next); | ||
794 | } while (el != start); | ||
795 | |||
796 | return NULL; | ||
797 | } | ||
798 | |||
799 | /** | ||
800 | * asd_ms_get_phy_params - get phy parameters from the manufacturing sector | ||
801 | * @asd_ha: pointer to the host adapter structure | ||
802 | * @manuf_sec: pointer to the manufacturing sector | ||
803 | * | ||
804 | * The manufacturing sector contans also the linked list of sub-segments, | ||
805 | * since when it was read, its size was taken from the flash directory, | ||
806 | * not from the structure size. | ||
807 | * | ||
808 | * HIDDEN phys do not count in the total count. REPORTED phys cannot | ||
809 | * be enabled but are reported and counted towards the total. | ||
810 | * ENEBLEABLE phys are enabled by default and count towards the total. | ||
811 | * The absolute total phy number is ASD_MAX_PHYS. hw_prof->num_phys | ||
812 | * merely specifies the number of phys the host adapter decided to | ||
813 | * report. E.g., it is possible for phys 0, 1 and 2 to be HIDDEN, | ||
814 | * phys 3, 4 and 5 to be REPORTED and phys 6 and 7 to be ENEBLEABLE. | ||
815 | * In this case ASD_MAX_PHYS is 8, hw_prof->num_phys is 5, and only 2 | ||
816 | * are actually enabled (enabled by default, max number of phys | ||
817 | * enableable in this case). | ||
818 | */ | ||
819 | static int asd_ms_get_phy_params(struct asd_ha_struct *asd_ha, | ||
820 | struct asd_manuf_sec *manuf_sec) | ||
821 | { | ||
822 | int i; | ||
823 | int en_phys = 0; | ||
824 | int rep_phys = 0; | ||
825 | struct asd_manuf_phy_param *phy_param; | ||
826 | struct asd_manuf_phy_param dflt_phy_param; | ||
827 | |||
828 | phy_param = asd_find_ll_by_id(manuf_sec, 'P', 'M'); | ||
829 | if (!phy_param) { | ||
830 | ASD_DPRINTK("ms: no phy parameters found\n"); | ||
831 | ASD_DPRINTK("ms: Creating default phy parameters\n"); | ||
832 | dflt_phy_param.sig[0] = 'P'; | ||
833 | dflt_phy_param.sig[1] = 'M'; | ||
834 | dflt_phy_param.maj = 0; | ||
835 | dflt_phy_param.min = 2; | ||
836 | dflt_phy_param.num_phy_desc = 8; | ||
837 | dflt_phy_param.phy_desc_size = sizeof(struct asd_manuf_phy_desc); | ||
838 | for (i =0; i < ASD_MAX_PHYS; i++) { | ||
839 | dflt_phy_param.phy_desc[i].state = 0; | ||
840 | dflt_phy_param.phy_desc[i].phy_id = i; | ||
841 | dflt_phy_param.phy_desc[i].phy_control_0 = 0xf6; | ||
842 | dflt_phy_param.phy_desc[i].phy_control_1 = 0x10; | ||
843 | dflt_phy_param.phy_desc[i].phy_control_2 = 0x43; | ||
844 | dflt_phy_param.phy_desc[i].phy_control_3 = 0xeb; | ||
845 | } | ||
846 | |||
847 | phy_param = &dflt_phy_param; | ||
848 | |||
849 | } | ||
850 | |||
851 | if (phy_param->maj != 0) { | ||
852 | asd_printk("unsupported manuf. phy param major version:0x%x\n", | ||
853 | phy_param->maj); | ||
854 | return -ENOENT; | ||
855 | } | ||
856 | |||
857 | ASD_DPRINTK("ms: num_phy_desc: %d\n", phy_param->num_phy_desc); | ||
858 | asd_ha->hw_prof.enabled_phys = 0; | ||
859 | for (i = 0; i < phy_param->num_phy_desc; i++) { | ||
860 | struct asd_manuf_phy_desc *pd = &phy_param->phy_desc[i]; | ||
861 | switch (pd->state & 0xF) { | ||
862 | case MS_PHY_STATE_HIDDEN: | ||
863 | ASD_DPRINTK("ms: phy%d: HIDDEN\n", i); | ||
864 | continue; | ||
865 | case MS_PHY_STATE_REPORTED: | ||
866 | ASD_DPRINTK("ms: phy%d: REPORTED\n", i); | ||
867 | asd_ha->hw_prof.enabled_phys &= ~(1 << i); | ||
868 | rep_phys++; | ||
869 | continue; | ||
870 | case MS_PHY_STATE_ENABLEABLE: | ||
871 | ASD_DPRINTK("ms: phy%d: ENEBLEABLE\n", i); | ||
872 | asd_ha->hw_prof.enabled_phys |= (1 << i); | ||
873 | en_phys++; | ||
874 | break; | ||
875 | } | ||
876 | asd_ha->hw_prof.phy_desc[i].phy_control_0 = pd->phy_control_0; | ||
877 | asd_ha->hw_prof.phy_desc[i].phy_control_1 = pd->phy_control_1; | ||
878 | asd_ha->hw_prof.phy_desc[i].phy_control_2 = pd->phy_control_2; | ||
879 | asd_ha->hw_prof.phy_desc[i].phy_control_3 = pd->phy_control_3; | ||
880 | } | ||
881 | asd_ha->hw_prof.max_phys = rep_phys + en_phys; | ||
882 | asd_ha->hw_prof.num_phys = en_phys; | ||
883 | ASD_DPRINTK("ms: max_phys:0x%x, num_phys:0x%x\n", | ||
884 | asd_ha->hw_prof.max_phys, asd_ha->hw_prof.num_phys); | ||
885 | ASD_DPRINTK("ms: enabled_phys:0x%x\n", asd_ha->hw_prof.enabled_phys); | ||
886 | return 0; | ||
887 | } | ||
888 | |||
889 | static int asd_ms_get_connector_map(struct asd_ha_struct *asd_ha, | ||
890 | struct asd_manuf_sec *manuf_sec) | ||
891 | { | ||
892 | struct asd_ms_conn_map *cm; | ||
893 | |||
894 | cm = asd_find_ll_by_id(manuf_sec, 'M', 'C'); | ||
895 | if (!cm) { | ||
896 | ASD_DPRINTK("ms: no connector map found\n"); | ||
897 | return 0; | ||
898 | } | ||
899 | |||
900 | if (cm->maj != 0) { | ||
901 | ASD_DPRINTK("ms: unsupported: connector map major version 0x%x" | ||
902 | "\n", cm->maj); | ||
903 | return -ENOENT; | ||
904 | } | ||
905 | |||
906 | /* XXX */ | ||
907 | |||
908 | return 0; | ||
909 | } | ||
910 | |||
911 | |||
912 | /** | ||
913 | * asd_process_ms - find and extract information from the manufacturing sector | ||
914 | * @asd_ha: pointer to the host adapter structure | ||
915 | * @flash_dir: pointer to the flash directory | ||
916 | */ | ||
917 | static int asd_process_ms(struct asd_ha_struct *asd_ha, | ||
918 | struct asd_flash_dir *flash_dir) | ||
919 | { | ||
920 | int err; | ||
921 | struct asd_manuf_sec *manuf_sec; | ||
922 | u32 offs, size; | ||
923 | |||
924 | err = asd_find_flash_de(flash_dir, FLASH_DE_MS, &offs, &size); | ||
925 | if (err) { | ||
926 | ASD_DPRINTK("Couldn't find the manuf. sector\n"); | ||
927 | goto out; | ||
928 | } | ||
929 | |||
930 | if (size == 0) | ||
931 | goto out; | ||
932 | |||
933 | err = -ENOMEM; | ||
934 | manuf_sec = kmalloc(size, GFP_KERNEL); | ||
935 | if (!manuf_sec) { | ||
936 | ASD_DPRINTK("no mem for manuf sector\n"); | ||
937 | goto out; | ||
938 | } | ||
939 | |||
940 | err = asd_read_flash_seg(asd_ha, (void *)manuf_sec, offs, size); | ||
941 | if (err) { | ||
942 | ASD_DPRINTK("couldn't read manuf sector at 0x%x, size 0x%x\n", | ||
943 | offs, size); | ||
944 | goto out2; | ||
945 | } | ||
946 | |||
947 | err = asd_validate_ms(manuf_sec); | ||
948 | if (err) { | ||
949 | ASD_DPRINTK("couldn't validate manuf sector\n"); | ||
950 | goto out2; | ||
951 | } | ||
952 | |||
953 | err = asd_ms_get_sas_addr(asd_ha, manuf_sec); | ||
954 | if (err) { | ||
955 | ASD_DPRINTK("couldn't read the SAS_ADDR\n"); | ||
956 | goto out2; | ||
957 | } | ||
958 | ASD_DPRINTK("manuf sect SAS_ADDR %llx\n", | ||
959 | SAS_ADDR(asd_ha->hw_prof.sas_addr)); | ||
960 | |||
961 | err = asd_ms_get_pcba_sn(asd_ha, manuf_sec); | ||
962 | if (err) { | ||
963 | ASD_DPRINTK("couldn't read the PCBA SN\n"); | ||
964 | goto out2; | ||
965 | } | ||
966 | ASD_DPRINTK("manuf sect PCBA SN %s\n", asd_ha->hw_prof.pcba_sn); | ||
967 | |||
968 | err = asd_ms_get_phy_params(asd_ha, manuf_sec); | ||
969 | if (err) { | ||
970 | ASD_DPRINTK("ms: couldn't get phy parameters\n"); | ||
971 | goto out2; | ||
972 | } | ||
973 | |||
974 | err = asd_ms_get_connector_map(asd_ha, manuf_sec); | ||
975 | if (err) { | ||
976 | ASD_DPRINTK("ms: couldn't get connector map\n"); | ||
977 | goto out2; | ||
978 | } | ||
979 | |||
980 | out2: | ||
981 | kfree(manuf_sec); | ||
982 | out: | ||
983 | return err; | ||
984 | } | ||
985 | |||
986 | static int asd_process_ctrla_phy_settings(struct asd_ha_struct *asd_ha, | ||
987 | struct asd_ctrla_phy_settings *ps) | ||
988 | { | ||
989 | int i; | ||
990 | for (i = 0; i < ps->num_phys; i++) { | ||
991 | struct asd_ctrla_phy_entry *pe = &ps->phy_ent[i]; | ||
992 | |||
993 | if (!PHY_ENABLED(asd_ha, i)) | ||
994 | continue; | ||
995 | if (*(u64 *)pe->sas_addr == 0) { | ||
996 | asd_ha->hw_prof.enabled_phys &= ~(1 << i); | ||
997 | continue; | ||
998 | } | ||
999 | /* This is the SAS address which should be sent in IDENTIFY. */ | ||
1000 | memcpy(asd_ha->hw_prof.phy_desc[i].sas_addr, pe->sas_addr, | ||
1001 | SAS_ADDR_SIZE); | ||
1002 | asd_ha->hw_prof.phy_desc[i].max_sas_lrate = | ||
1003 | (pe->sas_link_rates & 0xF0) >> 4; | ||
1004 | asd_ha->hw_prof.phy_desc[i].min_sas_lrate = | ||
1005 | (pe->sas_link_rates & 0x0F); | ||
1006 | asd_ha->hw_prof.phy_desc[i].max_sata_lrate = | ||
1007 | (pe->sata_link_rates & 0xF0) >> 4; | ||
1008 | asd_ha->hw_prof.phy_desc[i].min_sata_lrate = | ||
1009 | (pe->sata_link_rates & 0x0F); | ||
1010 | asd_ha->hw_prof.phy_desc[i].flags = pe->flags; | ||
1011 | ASD_DPRINTK("ctrla: phy%d: sas_addr: %llx, sas rate:0x%x-0x%x," | ||
1012 | " sata rate:0x%x-0x%x, flags:0x%x\n", | ||
1013 | i, | ||
1014 | SAS_ADDR(asd_ha->hw_prof.phy_desc[i].sas_addr), | ||
1015 | asd_ha->hw_prof.phy_desc[i].max_sas_lrate, | ||
1016 | asd_ha->hw_prof.phy_desc[i].min_sas_lrate, | ||
1017 | asd_ha->hw_prof.phy_desc[i].max_sata_lrate, | ||
1018 | asd_ha->hw_prof.phy_desc[i].min_sata_lrate, | ||
1019 | asd_ha->hw_prof.phy_desc[i].flags); | ||
1020 | } | ||
1021 | |||
1022 | return 0; | ||
1023 | } | ||
1024 | |||
1025 | /** | ||
1026 | * asd_process_ctrl_a_user - process CTRL-A user settings | ||
1027 | * @asd_ha: pointer to the host adapter structure | ||
1028 | * @flash_dir: pointer to the flash directory | ||
1029 | */ | ||
1030 | static int asd_process_ctrl_a_user(struct asd_ha_struct *asd_ha, | ||
1031 | struct asd_flash_dir *flash_dir) | ||
1032 | { | ||
1033 | int err, i; | ||
1034 | u32 offs, size; | ||
1035 | struct asd_ll_el *el; | ||
1036 | struct asd_ctrla_phy_settings *ps; | ||
1037 | struct asd_ctrla_phy_settings dflt_ps; | ||
1038 | |||
1039 | err = asd_find_flash_de(flash_dir, FLASH_DE_CTRL_A_USER, &offs, &size); | ||
1040 | if (err) { | ||
1041 | ASD_DPRINTK("couldn't find CTRL-A user settings section\n"); | ||
1042 | ASD_DPRINTK("Creating default CTRL-A user settings section\n"); | ||
1043 | |||
1044 | dflt_ps.id0 = 'h'; | ||
1045 | dflt_ps.num_phys = 8; | ||
1046 | for (i =0; i < ASD_MAX_PHYS; i++) { | ||
1047 | memcpy(dflt_ps.phy_ent[i].sas_addr, | ||
1048 | asd_ha->hw_prof.sas_addr, SAS_ADDR_SIZE); | ||
1049 | dflt_ps.phy_ent[i].sas_link_rates = 0x98; | ||
1050 | dflt_ps.phy_ent[i].flags = 0x0; | ||
1051 | dflt_ps.phy_ent[i].sata_link_rates = 0x0; | ||
1052 | } | ||
1053 | |||
1054 | size = sizeof(struct asd_ctrla_phy_settings); | ||
1055 | ps = &dflt_ps; | ||
1056 | } | ||
1057 | |||
1058 | if (size == 0) | ||
1059 | goto out; | ||
1060 | |||
1061 | err = -ENOMEM; | ||
1062 | el = kmalloc(size, GFP_KERNEL); | ||
1063 | if (!el) { | ||
1064 | ASD_DPRINTK("no mem for ctrla user settings section\n"); | ||
1065 | goto out; | ||
1066 | } | ||
1067 | |||
1068 | err = asd_read_flash_seg(asd_ha, (void *)el, offs, size); | ||
1069 | if (err) { | ||
1070 | ASD_DPRINTK("couldn't read ctrla phy settings section\n"); | ||
1071 | goto out2; | ||
1072 | } | ||
1073 | |||
1074 | err = -ENOENT; | ||
1075 | ps = asd_find_ll_by_id(el, 'h', 0xFF); | ||
1076 | if (!ps) { | ||
1077 | ASD_DPRINTK("couldn't find ctrla phy settings struct\n"); | ||
1078 | goto out2; | ||
1079 | } | ||
1080 | |||
1081 | err = asd_process_ctrla_phy_settings(asd_ha, ps); | ||
1082 | if (err) { | ||
1083 | ASD_DPRINTK("couldn't process ctrla phy settings\n"); | ||
1084 | goto out2; | ||
1085 | } | ||
1086 | out2: | ||
1087 | kfree(el); | ||
1088 | out: | ||
1089 | return err; | ||
1090 | } | ||
1091 | |||
1092 | /** | ||
1093 | * asd_read_flash - read flash memory | ||
1094 | * @asd_ha: pointer to the host adapter structure | ||
1095 | */ | ||
1096 | int asd_read_flash(struct asd_ha_struct *asd_ha) | ||
1097 | { | ||
1098 | int err; | ||
1099 | struct asd_flash_dir *flash_dir; | ||
1100 | |||
1101 | err = asd_flash_getid(asd_ha); | ||
1102 | if (err) | ||
1103 | return err; | ||
1104 | |||
1105 | flash_dir = kmalloc(sizeof(*flash_dir), GFP_KERNEL); | ||
1106 | if (!flash_dir) | ||
1107 | return -ENOMEM; | ||
1108 | |||
1109 | err = -ENOENT; | ||
1110 | if (!asd_find_flash_dir(asd_ha, flash_dir)) { | ||
1111 | ASD_DPRINTK("couldn't find flash directory\n"); | ||
1112 | goto out; | ||
1113 | } | ||
1114 | |||
1115 | if (le32_to_cpu(flash_dir->rev) != 2) { | ||
1116 | asd_printk("unsupported flash dir version:0x%x\n", | ||
1117 | le32_to_cpu(flash_dir->rev)); | ||
1118 | goto out; | ||
1119 | } | ||
1120 | |||
1121 | err = asd_process_ms(asd_ha, flash_dir); | ||
1122 | if (err) { | ||
1123 | ASD_DPRINTK("couldn't process manuf sector settings\n"); | ||
1124 | goto out; | ||
1125 | } | ||
1126 | |||
1127 | err = asd_process_ctrl_a_user(asd_ha, flash_dir); | ||
1128 | if (err) { | ||
1129 | ASD_DPRINTK("couldn't process CTRL-A user settings\n"); | ||
1130 | goto out; | ||
1131 | } | ||
1132 | |||
1133 | out: | ||
1134 | kfree(flash_dir); | ||
1135 | return err; | ||
1136 | } | ||
diff --git a/drivers/scsi/aic94xx/aic94xx_seq.c b/drivers/scsi/aic94xx/aic94xx_seq.c new file mode 100644 index 000000000000..9050c6f3f6bd --- /dev/null +++ b/drivers/scsi/aic94xx/aic94xx_seq.c | |||
@@ -0,0 +1,1401 @@ | |||
1 | /* | ||
2 | * Aic94xx SAS/SATA driver sequencer interface. | ||
3 | * | ||
4 | * Copyright (C) 2005 Adaptec, Inc. All rights reserved. | ||
5 | * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> | ||
6 | * | ||
7 | * Parts of this code adapted from David Chaw's adp94xx_seq.c. | ||
8 | * | ||
9 | * This file is licensed under GPLv2. | ||
10 | * | ||
11 | * This file is part of the aic94xx driver. | ||
12 | * | ||
13 | * The aic94xx driver is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License as | ||
15 | * published by the Free Software Foundation; version 2 of the | ||
16 | * License. | ||
17 | * | ||
18 | * The aic94xx driver is distributed in the hope that it will be useful, | ||
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
21 | * General Public License for more details. | ||
22 | * | ||
23 | * You should have received a copy of the GNU General Public License | ||
24 | * along with the aic94xx driver; if not, write to the Free Software | ||
25 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
26 | * | ||
27 | */ | ||
28 | |||
29 | #include <linux/delay.h> | ||
30 | #include <linux/pci.h> | ||
31 | #include <linux/firmware.h> | ||
32 | #include "aic94xx_reg.h" | ||
33 | #include "aic94xx_hwi.h" | ||
34 | |||
35 | #include "aic94xx_seq.h" | ||
36 | #include "aic94xx_dump.h" | ||
37 | |||
38 | /* It takes no more than 0.05 us for an instruction | ||
39 | * to complete. So waiting for 1 us should be more than | ||
40 | * plenty. | ||
41 | */ | ||
42 | #define PAUSE_DELAY 1 | ||
43 | #define PAUSE_TRIES 1000 | ||
44 | |||
45 | static const struct firmware *sequencer_fw; | ||
46 | static const char *sequencer_version; | ||
47 | static u16 cseq_vecs[CSEQ_NUM_VECS], lseq_vecs[LSEQ_NUM_VECS], mode2_task, | ||
48 | cseq_idle_loop, lseq_idle_loop; | ||
49 | static u8 *cseq_code, *lseq_code; | ||
50 | static u32 cseq_code_size, lseq_code_size; | ||
51 | |||
52 | static u16 first_scb_site_no = 0xFFFF; | ||
53 | static u16 last_scb_site_no; | ||
54 | |||
55 | /* ---------- Pause/Unpause CSEQ/LSEQ ---------- */ | ||
56 | |||
57 | /** | ||
58 | * asd_pause_cseq - pause the central sequencer | ||
59 | * @asd_ha: pointer to host adapter structure | ||
60 | * | ||
61 | * Return 0 on success, negative on failure. | ||
62 | */ | ||
63 | int asd_pause_cseq(struct asd_ha_struct *asd_ha) | ||
64 | { | ||
65 | int count = PAUSE_TRIES; | ||
66 | u32 arp2ctl; | ||
67 | |||
68 | arp2ctl = asd_read_reg_dword(asd_ha, CARP2CTL); | ||
69 | if (arp2ctl & PAUSED) | ||
70 | return 0; | ||
71 | |||
72 | asd_write_reg_dword(asd_ha, CARP2CTL, arp2ctl | EPAUSE); | ||
73 | do { | ||
74 | arp2ctl = asd_read_reg_dword(asd_ha, CARP2CTL); | ||
75 | if (arp2ctl & PAUSED) | ||
76 | return 0; | ||
77 | udelay(PAUSE_DELAY); | ||
78 | } while (--count > 0); | ||
79 | |||
80 | ASD_DPRINTK("couldn't pause CSEQ\n"); | ||
81 | return -1; | ||
82 | } | ||
83 | |||
84 | /** | ||
85 | * asd_unpause_cseq - unpause the central sequencer. | ||
86 | * @asd_ha: pointer to host adapter structure. | ||
87 | * | ||
88 | * Return 0 on success, negative on error. | ||
89 | */ | ||
90 | int asd_unpause_cseq(struct asd_ha_struct *asd_ha) | ||
91 | { | ||
92 | u32 arp2ctl; | ||
93 | int count = PAUSE_TRIES; | ||
94 | |||
95 | arp2ctl = asd_read_reg_dword(asd_ha, CARP2CTL); | ||
96 | if (!(arp2ctl & PAUSED)) | ||
97 | return 0; | ||
98 | |||
99 | asd_write_reg_dword(asd_ha, CARP2CTL, arp2ctl & ~EPAUSE); | ||
100 | do { | ||
101 | arp2ctl = asd_read_reg_dword(asd_ha, CARP2CTL); | ||
102 | if (!(arp2ctl & PAUSED)) | ||
103 | return 0; | ||
104 | udelay(PAUSE_DELAY); | ||
105 | } while (--count > 0); | ||
106 | |||
107 | ASD_DPRINTK("couldn't unpause the CSEQ\n"); | ||
108 | return -1; | ||
109 | } | ||
110 | |||
111 | /** | ||
112 | * asd_seq_pause_lseq - pause a link sequencer | ||
113 | * @asd_ha: pointer to a host adapter structure | ||
114 | * @lseq: link sequencer of interest | ||
115 | * | ||
116 | * Return 0 on success, negative on error. | ||
117 | */ | ||
118 | static inline int asd_seq_pause_lseq(struct asd_ha_struct *asd_ha, int lseq) | ||
119 | { | ||
120 | u32 arp2ctl; | ||
121 | int count = PAUSE_TRIES; | ||
122 | |||
123 | arp2ctl = asd_read_reg_dword(asd_ha, LmARP2CTL(lseq)); | ||
124 | if (arp2ctl & PAUSED) | ||
125 | return 0; | ||
126 | |||
127 | asd_write_reg_dword(asd_ha, LmARP2CTL(lseq), arp2ctl | EPAUSE); | ||
128 | do { | ||
129 | arp2ctl = asd_read_reg_dword(asd_ha, LmARP2CTL(lseq)); | ||
130 | if (arp2ctl & PAUSED) | ||
131 | return 0; | ||
132 | udelay(PAUSE_DELAY); | ||
133 | } while (--count > 0); | ||
134 | |||
135 | ASD_DPRINTK("couldn't pause LSEQ %d\n", lseq); | ||
136 | return -1; | ||
137 | } | ||
138 | |||
139 | /** | ||
140 | * asd_pause_lseq - pause the link sequencer(s) | ||
141 | * @asd_ha: pointer to host adapter structure | ||
142 | * @lseq_mask: mask of link sequencers of interest | ||
143 | * | ||
144 | * Return 0 on success, negative on failure. | ||
145 | */ | ||
146 | int asd_pause_lseq(struct asd_ha_struct *asd_ha, u8 lseq_mask) | ||
147 | { | ||
148 | int lseq; | ||
149 | int err = 0; | ||
150 | |||
151 | for_each_sequencer(lseq_mask, lseq_mask, lseq) { | ||
152 | err = asd_seq_pause_lseq(asd_ha, lseq); | ||
153 | if (err) | ||
154 | return err; | ||
155 | } | ||
156 | |||
157 | return err; | ||
158 | } | ||
159 | |||
160 | /** | ||
161 | * asd_seq_unpause_lseq - unpause a link sequencer | ||
162 | * @asd_ha: pointer to host adapter structure | ||
163 | * @lseq: link sequencer of interest | ||
164 | * | ||
165 | * Return 0 on success, negative on error. | ||
166 | */ | ||
167 | static inline int asd_seq_unpause_lseq(struct asd_ha_struct *asd_ha, int lseq) | ||
168 | { | ||
169 | u32 arp2ctl; | ||
170 | int count = PAUSE_TRIES; | ||
171 | |||
172 | arp2ctl = asd_read_reg_dword(asd_ha, LmARP2CTL(lseq)); | ||
173 | if (!(arp2ctl & PAUSED)) | ||
174 | return 0; | ||
175 | |||
176 | asd_write_reg_dword(asd_ha, LmARP2CTL(lseq), arp2ctl & ~EPAUSE); | ||
177 | do { | ||
178 | arp2ctl = asd_read_reg_dword(asd_ha, LmARP2CTL(lseq)); | ||
179 | if (!(arp2ctl & PAUSED)) | ||
180 | return 0; | ||
181 | udelay(PAUSE_DELAY); | ||
182 | } while (--count > 0); | ||
183 | |||
184 | ASD_DPRINTK("couldn't unpause LSEQ %d\n", lseq); | ||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | |||
189 | /** | ||
190 | * asd_unpause_lseq - unpause the link sequencer(s) | ||
191 | * @asd_ha: pointer to host adapter structure | ||
192 | * @lseq_mask: mask of link sequencers of interest | ||
193 | * | ||
194 | * Return 0 on success, negative on failure. | ||
195 | */ | ||
196 | int asd_unpause_lseq(struct asd_ha_struct *asd_ha, u8 lseq_mask) | ||
197 | { | ||
198 | int lseq; | ||
199 | int err = 0; | ||
200 | |||
201 | for_each_sequencer(lseq_mask, lseq_mask, lseq) { | ||
202 | err = asd_seq_unpause_lseq(asd_ha, lseq); | ||
203 | if (err) | ||
204 | return err; | ||
205 | } | ||
206 | |||
207 | return err; | ||
208 | } | ||
209 | |||
210 | /* ---------- Downloading CSEQ/LSEQ microcode ---------- */ | ||
211 | |||
212 | static int asd_verify_cseq(struct asd_ha_struct *asd_ha, const u8 *_prog, | ||
213 | u32 size) | ||
214 | { | ||
215 | u32 addr = CSEQ_RAM_REG_BASE_ADR; | ||
216 | const u32 *prog = (u32 *) _prog; | ||
217 | u32 i; | ||
218 | |||
219 | for (i = 0; i < size; i += 4, prog++, addr += 4) { | ||
220 | u32 val = asd_read_reg_dword(asd_ha, addr); | ||
221 | |||
222 | if (le32_to_cpu(*prog) != val) { | ||
223 | asd_printk("%s: cseq verify failed at %u " | ||
224 | "read:0x%x, wanted:0x%x\n", | ||
225 | pci_name(asd_ha->pcidev), | ||
226 | i, val, le32_to_cpu(*prog)); | ||
227 | return -1; | ||
228 | } | ||
229 | } | ||
230 | ASD_DPRINTK("verified %d bytes, passed\n", size); | ||
231 | return 0; | ||
232 | } | ||
233 | |||
234 | /** | ||
235 | * asd_verify_lseq - verify the microcode of a link sequencer | ||
236 | * @asd_ha: pointer to host adapter structure | ||
237 | * @_prog: pointer to the microcode | ||
238 | * @size: size of the microcode in bytes | ||
239 | * @lseq: link sequencer of interest | ||
240 | * | ||
241 | * The link sequencer code is accessed in 4 KB pages, which are selected | ||
242 | * by setting LmRAMPAGE (bits 8 and 9) of the LmBISTCTL1 register. | ||
243 | * The 10 KB LSEQm instruction code is mapped, page at a time, at | ||
244 | * LmSEQRAM address. | ||
245 | */ | ||
246 | static int asd_verify_lseq(struct asd_ha_struct *asd_ha, const u8 *_prog, | ||
247 | u32 size, int lseq) | ||
248 | { | ||
249 | #define LSEQ_CODEPAGE_SIZE 4096 | ||
250 | int pages = (size + LSEQ_CODEPAGE_SIZE - 1) / LSEQ_CODEPAGE_SIZE; | ||
251 | u32 page; | ||
252 | const u32 *prog = (u32 *) _prog; | ||
253 | |||
254 | for (page = 0; page < pages; page++) { | ||
255 | u32 i; | ||
256 | |||
257 | asd_write_reg_dword(asd_ha, LmBISTCTL1(lseq), | ||
258 | page << LmRAMPAGE_LSHIFT); | ||
259 | for (i = 0; size > 0 && i < LSEQ_CODEPAGE_SIZE; | ||
260 | i += 4, prog++, size-=4) { | ||
261 | |||
262 | u32 val = asd_read_reg_dword(asd_ha, LmSEQRAM(lseq)+i); | ||
263 | |||
264 | if (le32_to_cpu(*prog) != val) { | ||
265 | asd_printk("%s: LSEQ%d verify failed " | ||
266 | "page:%d, offs:%d\n", | ||
267 | pci_name(asd_ha->pcidev), | ||
268 | lseq, page, i); | ||
269 | return -1; | ||
270 | } | ||
271 | } | ||
272 | } | ||
273 | ASD_DPRINTK("LSEQ%d verified %d bytes, passed\n", lseq, | ||
274 | (int)((u8 *)prog-_prog)); | ||
275 | return 0; | ||
276 | } | ||
277 | |||
278 | /** | ||
279 | * asd_verify_seq -- verify CSEQ/LSEQ microcode | ||
280 | * @asd_ha: pointer to host adapter structure | ||
281 | * @prog: pointer to microcode | ||
282 | * @size: size of the microcode | ||
283 | * @lseq_mask: if 0, verify CSEQ microcode, else mask of LSEQs of interest | ||
284 | * | ||
285 | * Return 0 if microcode is correct, negative on mismatch. | ||
286 | */ | ||
287 | static int asd_verify_seq(struct asd_ha_struct *asd_ha, const u8 *prog, | ||
288 | u32 size, u8 lseq_mask) | ||
289 | { | ||
290 | if (lseq_mask == 0) | ||
291 | return asd_verify_cseq(asd_ha, prog, size); | ||
292 | else { | ||
293 | int lseq, err; | ||
294 | |||
295 | for_each_sequencer(lseq_mask, lseq_mask, lseq) { | ||
296 | err = asd_verify_lseq(asd_ha, prog, size, lseq); | ||
297 | if (err) | ||
298 | return err; | ||
299 | } | ||
300 | } | ||
301 | |||
302 | return 0; | ||
303 | } | ||
304 | #define ASD_DMA_MODE_DOWNLOAD | ||
305 | #ifdef ASD_DMA_MODE_DOWNLOAD | ||
306 | /* This is the size of the CSEQ Mapped instruction page */ | ||
307 | #define MAX_DMA_OVLY_COUNT ((1U << 14)-1) | ||
308 | static int asd_download_seq(struct asd_ha_struct *asd_ha, | ||
309 | const u8 * const prog, u32 size, u8 lseq_mask) | ||
310 | { | ||
311 | u32 comstaten; | ||
312 | u32 reg; | ||
313 | int page; | ||
314 | const int pages = (size + MAX_DMA_OVLY_COUNT - 1) / MAX_DMA_OVLY_COUNT; | ||
315 | struct asd_dma_tok *token; | ||
316 | int err = 0; | ||
317 | |||
318 | if (size % 4) { | ||
319 | asd_printk("sequencer program not multiple of 4\n"); | ||
320 | return -1; | ||
321 | } | ||
322 | |||
323 | asd_pause_cseq(asd_ha); | ||
324 | asd_pause_lseq(asd_ha, 0xFF); | ||
325 | |||
326 | /* save, disable and clear interrupts */ | ||
327 | comstaten = asd_read_reg_dword(asd_ha, COMSTATEN); | ||
328 | asd_write_reg_dword(asd_ha, COMSTATEN, 0); | ||
329 | asd_write_reg_dword(asd_ha, COMSTAT, COMSTAT_MASK); | ||
330 | |||
331 | asd_write_reg_dword(asd_ha, CHIMINTEN, RST_CHIMINTEN); | ||
332 | asd_write_reg_dword(asd_ha, CHIMINT, CHIMINT_MASK); | ||
333 | |||
334 | token = asd_alloc_coherent(asd_ha, MAX_DMA_OVLY_COUNT, GFP_KERNEL); | ||
335 | if (!token) { | ||
336 | asd_printk("out of memory for dma SEQ download\n"); | ||
337 | err = -ENOMEM; | ||
338 | goto out; | ||
339 | } | ||
340 | ASD_DPRINTK("dma-ing %d bytes\n", size); | ||
341 | |||
342 | for (page = 0; page < pages; page++) { | ||
343 | int i; | ||
344 | u32 left = min(size-page*MAX_DMA_OVLY_COUNT, | ||
345 | (u32)MAX_DMA_OVLY_COUNT); | ||
346 | |||
347 | memcpy(token->vaddr, prog + page*MAX_DMA_OVLY_COUNT, left); | ||
348 | asd_write_reg_addr(asd_ha, OVLYDMAADR, token->dma_handle); | ||
349 | asd_write_reg_dword(asd_ha, OVLYDMACNT, left); | ||
350 | reg = !page ? RESETOVLYDMA : 0; | ||
351 | reg |= (STARTOVLYDMA | OVLYHALTERR); | ||
352 | reg |= (lseq_mask ? (((u32)lseq_mask) << 8) : OVLYCSEQ); | ||
353 | /* Start DMA. */ | ||
354 | asd_write_reg_dword(asd_ha, OVLYDMACTL, reg); | ||
355 | |||
356 | for (i = PAUSE_TRIES*100; i > 0; i--) { | ||
357 | u32 dmadone = asd_read_reg_dword(asd_ha, OVLYDMACTL); | ||
358 | if (!(dmadone & OVLYDMAACT)) | ||
359 | break; | ||
360 | udelay(PAUSE_DELAY); | ||
361 | } | ||
362 | } | ||
363 | |||
364 | reg = asd_read_reg_dword(asd_ha, COMSTAT); | ||
365 | if (!(reg & OVLYDMADONE) || (reg & OVLYERR) | ||
366 | || (asd_read_reg_dword(asd_ha, CHIMINT) & DEVEXCEPT_MASK)){ | ||
367 | asd_printk("%s: error DMA-ing sequencer code\n", | ||
368 | pci_name(asd_ha->pcidev)); | ||
369 | err = -ENODEV; | ||
370 | } | ||
371 | |||
372 | asd_free_coherent(asd_ha, token); | ||
373 | out: | ||
374 | asd_write_reg_dword(asd_ha, COMSTATEN, comstaten); | ||
375 | |||
376 | return err ? : asd_verify_seq(asd_ha, prog, size, lseq_mask); | ||
377 | } | ||
378 | #else /* ASD_DMA_MODE_DOWNLOAD */ | ||
379 | static int asd_download_seq(struct asd_ha_struct *asd_ha, const u8 *_prog, | ||
380 | u32 size, u8 lseq_mask) | ||
381 | { | ||
382 | int i; | ||
383 | u32 reg = 0; | ||
384 | const u32 *prog = (u32 *) _prog; | ||
385 | |||
386 | if (size % 4) { | ||
387 | asd_printk("sequencer program not multiple of 4\n"); | ||
388 | return -1; | ||
389 | } | ||
390 | |||
391 | asd_pause_cseq(asd_ha); | ||
392 | asd_pause_lseq(asd_ha, 0xFF); | ||
393 | |||
394 | reg |= (lseq_mask ? (((u32)lseq_mask) << 8) : OVLYCSEQ); | ||
395 | reg |= PIOCMODE; | ||
396 | |||
397 | asd_write_reg_dword(asd_ha, OVLYDMACNT, size); | ||
398 | asd_write_reg_dword(asd_ha, OVLYDMACTL, reg); | ||
399 | |||
400 | ASD_DPRINTK("downloading %s sequencer%s in PIO mode...\n", | ||
401 | lseq_mask ? "LSEQ" : "CSEQ", lseq_mask ? "s" : ""); | ||
402 | |||
403 | for (i = 0; i < size; i += 4, prog++) | ||
404 | asd_write_reg_dword(asd_ha, SPIODATA, *prog); | ||
405 | |||
406 | reg = (reg & ~PIOCMODE) | OVLYHALTERR; | ||
407 | asd_write_reg_dword(asd_ha, OVLYDMACTL, reg); | ||
408 | |||
409 | return asd_verify_seq(asd_ha, _prog, size, lseq_mask); | ||
410 | } | ||
411 | #endif /* ASD_DMA_MODE_DOWNLOAD */ | ||
412 | |||
413 | /** | ||
414 | * asd_seq_download_seqs - download the sequencer microcode | ||
415 | * @asd_ha: pointer to host adapter structure | ||
416 | * | ||
417 | * Download the central and link sequencer microcode. | ||
418 | */ | ||
419 | static int asd_seq_download_seqs(struct asd_ha_struct *asd_ha) | ||
420 | { | ||
421 | int err; | ||
422 | |||
423 | if (!asd_ha->hw_prof.enabled_phys) { | ||
424 | asd_printk("%s: no enabled phys!\n", pci_name(asd_ha->pcidev)); | ||
425 | return -ENODEV; | ||
426 | } | ||
427 | |||
428 | /* Download the CSEQ */ | ||
429 | ASD_DPRINTK("downloading CSEQ...\n"); | ||
430 | err = asd_download_seq(asd_ha, cseq_code, cseq_code_size, 0); | ||
431 | if (err) { | ||
432 | asd_printk("CSEQ download failed:%d\n", err); | ||
433 | return err; | ||
434 | } | ||
435 | |||
436 | /* Download the Link Sequencers code. All of the Link Sequencers | ||
437 | * microcode can be downloaded at the same time. | ||
438 | */ | ||
439 | ASD_DPRINTK("downloading LSEQs...\n"); | ||
440 | err = asd_download_seq(asd_ha, lseq_code, lseq_code_size, | ||
441 | asd_ha->hw_prof.enabled_phys); | ||
442 | if (err) { | ||
443 | /* Try it one at a time */ | ||
444 | u8 lseq; | ||
445 | u8 lseq_mask = asd_ha->hw_prof.enabled_phys; | ||
446 | |||
447 | for_each_sequencer(lseq_mask, lseq_mask, lseq) { | ||
448 | err = asd_download_seq(asd_ha, lseq_code, | ||
449 | lseq_code_size, 1<<lseq); | ||
450 | if (err) | ||
451 | break; | ||
452 | } | ||
453 | } | ||
454 | if (err) | ||
455 | asd_printk("LSEQs download failed:%d\n", err); | ||
456 | |||
457 | return err; | ||
458 | } | ||
459 | |||
460 | /* ---------- Initializing the chip, chip memory, etc. ---------- */ | ||
461 | |||
462 | /** | ||
463 | * asd_init_cseq_mip - initialize CSEQ mode independent pages 4-7 | ||
464 | * @asd_ha: pointer to host adapter structure | ||
465 | */ | ||
466 | static void asd_init_cseq_mip(struct asd_ha_struct *asd_ha) | ||
467 | { | ||
468 | /* CSEQ Mode Independent, page 4 setup. */ | ||
469 | asd_write_reg_word(asd_ha, CSEQ_Q_EXE_HEAD, 0xFFFF); | ||
470 | asd_write_reg_word(asd_ha, CSEQ_Q_EXE_TAIL, 0xFFFF); | ||
471 | asd_write_reg_word(asd_ha, CSEQ_Q_DONE_HEAD, 0xFFFF); | ||
472 | asd_write_reg_word(asd_ha, CSEQ_Q_DONE_TAIL, 0xFFFF); | ||
473 | asd_write_reg_word(asd_ha, CSEQ_Q_SEND_HEAD, 0xFFFF); | ||
474 | asd_write_reg_word(asd_ha, CSEQ_Q_SEND_TAIL, 0xFFFF); | ||
475 | asd_write_reg_word(asd_ha, CSEQ_Q_DMA2CHIM_HEAD, 0xFFFF); | ||
476 | asd_write_reg_word(asd_ha, CSEQ_Q_DMA2CHIM_TAIL, 0xFFFF); | ||
477 | asd_write_reg_word(asd_ha, CSEQ_Q_COPY_HEAD, 0xFFFF); | ||
478 | asd_write_reg_word(asd_ha, CSEQ_Q_COPY_TAIL, 0xFFFF); | ||
479 | asd_write_reg_word(asd_ha, CSEQ_REG0, 0); | ||
480 | asd_write_reg_word(asd_ha, CSEQ_REG1, 0); | ||
481 | asd_write_reg_dword(asd_ha, CSEQ_REG2, 0); | ||
482 | asd_write_reg_byte(asd_ha, CSEQ_LINK_CTL_Q_MAP, 0); | ||
483 | { | ||
484 | u8 con = asd_read_reg_byte(asd_ha, CCONEXIST); | ||
485 | u8 val = hweight8(con); | ||
486 | asd_write_reg_byte(asd_ha, CSEQ_MAX_CSEQ_MODE, (val<<4)|val); | ||
487 | } | ||
488 | asd_write_reg_word(asd_ha, CSEQ_FREE_LIST_HACK_COUNT, 0); | ||
489 | |||
490 | /* CSEQ Mode independent, page 5 setup. */ | ||
491 | asd_write_reg_dword(asd_ha, CSEQ_EST_NEXUS_REQ_QUEUE, 0); | ||
492 | asd_write_reg_dword(asd_ha, CSEQ_EST_NEXUS_REQ_QUEUE+4, 0); | ||
493 | asd_write_reg_dword(asd_ha, CSEQ_EST_NEXUS_REQ_COUNT, 0); | ||
494 | asd_write_reg_dword(asd_ha, CSEQ_EST_NEXUS_REQ_COUNT+4, 0); | ||
495 | asd_write_reg_word(asd_ha, CSEQ_Q_EST_NEXUS_HEAD, 0xFFFF); | ||
496 | asd_write_reg_word(asd_ha, CSEQ_Q_EST_NEXUS_TAIL, 0xFFFF); | ||
497 | asd_write_reg_word(asd_ha, CSEQ_NEED_EST_NEXUS_SCB, 0); | ||
498 | asd_write_reg_byte(asd_ha, CSEQ_EST_NEXUS_REQ_HEAD, 0); | ||
499 | asd_write_reg_byte(asd_ha, CSEQ_EST_NEXUS_REQ_TAIL, 0); | ||
500 | asd_write_reg_byte(asd_ha, CSEQ_EST_NEXUS_SCB_OFFSET, 0); | ||
501 | |||
502 | /* CSEQ Mode independent, page 6 setup. */ | ||
503 | asd_write_reg_word(asd_ha, CSEQ_INT_ROUT_RET_ADDR0, 0); | ||
504 | asd_write_reg_word(asd_ha, CSEQ_INT_ROUT_RET_ADDR1, 0); | ||
505 | asd_write_reg_word(asd_ha, CSEQ_INT_ROUT_SCBPTR, 0); | ||
506 | asd_write_reg_byte(asd_ha, CSEQ_INT_ROUT_MODE, 0); | ||
507 | asd_write_reg_byte(asd_ha, CSEQ_ISR_SCRATCH_FLAGS, 0); | ||
508 | asd_write_reg_word(asd_ha, CSEQ_ISR_SAVE_SINDEX, 0); | ||
509 | asd_write_reg_word(asd_ha, CSEQ_ISR_SAVE_DINDEX, 0); | ||
510 | asd_write_reg_word(asd_ha, CSEQ_Q_MONIRTT_HEAD, 0xFFFF); | ||
511 | asd_write_reg_word(asd_ha, CSEQ_Q_MONIRTT_TAIL, 0xFFFF); | ||
512 | /* Calculate the free scb mask. */ | ||
513 | { | ||
514 | u16 cmdctx = asd_get_cmdctx_size(asd_ha); | ||
515 | cmdctx = (~((cmdctx/128)-1)) >> 8; | ||
516 | asd_write_reg_byte(asd_ha, CSEQ_FREE_SCB_MASK, (u8)cmdctx); | ||
517 | } | ||
518 | asd_write_reg_word(asd_ha, CSEQ_BUILTIN_FREE_SCB_HEAD, | ||
519 | first_scb_site_no); | ||
520 | asd_write_reg_word(asd_ha, CSEQ_BUILTIN_FREE_SCB_TAIL, | ||
521 | last_scb_site_no); | ||
522 | asd_write_reg_word(asd_ha, CSEQ_EXTENDED_FREE_SCB_HEAD, 0xFFFF); | ||
523 | asd_write_reg_word(asd_ha, CSEQ_EXTENDED_FREE_SCB_TAIL, 0xFFFF); | ||
524 | |||
525 | /* CSEQ Mode independent, page 7 setup. */ | ||
526 | asd_write_reg_dword(asd_ha, CSEQ_EMPTY_REQ_QUEUE, 0); | ||
527 | asd_write_reg_dword(asd_ha, CSEQ_EMPTY_REQ_QUEUE+4, 0); | ||
528 | asd_write_reg_dword(asd_ha, CSEQ_EMPTY_REQ_COUNT, 0); | ||
529 | asd_write_reg_dword(asd_ha, CSEQ_EMPTY_REQ_COUNT+4, 0); | ||
530 | asd_write_reg_word(asd_ha, CSEQ_Q_EMPTY_HEAD, 0xFFFF); | ||
531 | asd_write_reg_word(asd_ha, CSEQ_Q_EMPTY_TAIL, 0xFFFF); | ||
532 | asd_write_reg_word(asd_ha, CSEQ_NEED_EMPTY_SCB, 0); | ||
533 | asd_write_reg_byte(asd_ha, CSEQ_EMPTY_REQ_HEAD, 0); | ||
534 | asd_write_reg_byte(asd_ha, CSEQ_EMPTY_REQ_TAIL, 0); | ||
535 | asd_write_reg_byte(asd_ha, CSEQ_EMPTY_SCB_OFFSET, 0); | ||
536 | asd_write_reg_word(asd_ha, CSEQ_PRIMITIVE_DATA, 0); | ||
537 | asd_write_reg_dword(asd_ha, CSEQ_TIMEOUT_CONST, 0); | ||
538 | } | ||
539 | |||
540 | /** | ||
541 | * asd_init_cseq_mdp - initialize CSEQ Mode dependent pages | ||
542 | * @asd_ha: pointer to host adapter structure | ||
543 | */ | ||
544 | static void asd_init_cseq_mdp(struct asd_ha_struct *asd_ha) | ||
545 | { | ||
546 | int i; | ||
547 | int moffs; | ||
548 | |||
549 | moffs = CSEQ_PAGE_SIZE * 2; | ||
550 | |||
551 | /* CSEQ Mode dependent, modes 0-7, page 0 setup. */ | ||
552 | for (i = 0; i < 8; i++) { | ||
553 | asd_write_reg_word(asd_ha, i*moffs+CSEQ_LRM_SAVE_SINDEX, 0); | ||
554 | asd_write_reg_word(asd_ha, i*moffs+CSEQ_LRM_SAVE_SCBPTR, 0); | ||
555 | asd_write_reg_word(asd_ha, i*moffs+CSEQ_Q_LINK_HEAD, 0xFFFF); | ||
556 | asd_write_reg_word(asd_ha, i*moffs+CSEQ_Q_LINK_TAIL, 0xFFFF); | ||
557 | asd_write_reg_byte(asd_ha, i*moffs+CSEQ_LRM_SAVE_SCRPAGE, 0); | ||
558 | } | ||
559 | |||
560 | /* CSEQ Mode dependent, mode 0-7, page 1 and 2 shall be ignored. */ | ||
561 | |||
562 | /* CSEQ Mode dependent, mode 8, page 0 setup. */ | ||
563 | asd_write_reg_word(asd_ha, CSEQ_RET_ADDR, 0xFFFF); | ||
564 | asd_write_reg_word(asd_ha, CSEQ_RET_SCBPTR, 0); | ||
565 | asd_write_reg_word(asd_ha, CSEQ_SAVE_SCBPTR, 0); | ||
566 | asd_write_reg_word(asd_ha, CSEQ_EMPTY_TRANS_CTX, 0); | ||
567 | asd_write_reg_word(asd_ha, CSEQ_RESP_LEN, 0); | ||
568 | asd_write_reg_word(asd_ha, CSEQ_TMF_SCBPTR, 0); | ||
569 | asd_write_reg_word(asd_ha, CSEQ_GLOBAL_PREV_SCB, 0); | ||
570 | asd_write_reg_word(asd_ha, CSEQ_GLOBAL_HEAD, 0); | ||
571 | asd_write_reg_word(asd_ha, CSEQ_CLEAR_LU_HEAD, 0); | ||
572 | asd_write_reg_byte(asd_ha, CSEQ_TMF_OPCODE, 0); | ||
573 | asd_write_reg_byte(asd_ha, CSEQ_SCRATCH_FLAGS, 0); | ||
574 | asd_write_reg_word(asd_ha, CSEQ_HSB_SITE, 0); | ||
575 | asd_write_reg_word(asd_ha, CSEQ_FIRST_INV_SCB_SITE, | ||
576 | (u16)last_scb_site_no+1); | ||
577 | asd_write_reg_word(asd_ha, CSEQ_FIRST_INV_DDB_SITE, | ||
578 | (u16)asd_ha->hw_prof.max_ddbs); | ||
579 | |||
580 | /* CSEQ Mode dependent, mode 8, page 1 setup. */ | ||
581 | asd_write_reg_dword(asd_ha, CSEQ_LUN_TO_CLEAR, 0); | ||
582 | asd_write_reg_dword(asd_ha, CSEQ_LUN_TO_CLEAR + 4, 0); | ||
583 | asd_write_reg_dword(asd_ha, CSEQ_LUN_TO_CHECK, 0); | ||
584 | asd_write_reg_dword(asd_ha, CSEQ_LUN_TO_CHECK + 4, 0); | ||
585 | |||
586 | /* CSEQ Mode dependent, mode 8, page 2 setup. */ | ||
587 | /* Tell the sequencer the bus address of the first SCB. */ | ||
588 | asd_write_reg_addr(asd_ha, CSEQ_HQ_NEW_POINTER, | ||
589 | asd_ha->seq.next_scb.dma_handle); | ||
590 | ASD_DPRINTK("First SCB dma_handle: 0x%llx\n", | ||
591 | (unsigned long long)asd_ha->seq.next_scb.dma_handle); | ||
592 | |||
593 | /* Tell the sequencer the first Done List entry address. */ | ||
594 | asd_write_reg_addr(asd_ha, CSEQ_HQ_DONE_BASE, | ||
595 | asd_ha->seq.actual_dl->dma_handle); | ||
596 | |||
597 | /* Initialize the Q_DONE_POINTER with the least significant | ||
598 | * 4 bytes of the first Done List address. */ | ||
599 | asd_write_reg_dword(asd_ha, CSEQ_HQ_DONE_POINTER, | ||
600 | ASD_BUSADDR_LO(asd_ha->seq.actual_dl->dma_handle)); | ||
601 | |||
602 | asd_write_reg_byte(asd_ha, CSEQ_HQ_DONE_PASS, ASD_DEF_DL_TOGGLE); | ||
603 | |||
604 | /* CSEQ Mode dependent, mode 8, page 3 shall be ignored. */ | ||
605 | } | ||
606 | |||
607 | /** | ||
608 | * asd_init_cseq_scratch -- setup and init CSEQ | ||
609 | * @asd_ha: pointer to host adapter structure | ||
610 | * | ||
611 | * Setup and initialize Central sequencers. Initialiaze the mode | ||
612 | * independent and dependent scratch page to the default settings. | ||
613 | */ | ||
614 | static void asd_init_cseq_scratch(struct asd_ha_struct *asd_ha) | ||
615 | { | ||
616 | asd_init_cseq_mip(asd_ha); | ||
617 | asd_init_cseq_mdp(asd_ha); | ||
618 | } | ||
619 | |||
620 | /** | ||
621 | * asd_init_lseq_mip -- initialize LSEQ Mode independent pages 0-3 | ||
622 | * @asd_ha: pointer to host adapter structure | ||
623 | */ | ||
624 | static void asd_init_lseq_mip(struct asd_ha_struct *asd_ha, u8 lseq) | ||
625 | { | ||
626 | int i; | ||
627 | |||
628 | /* LSEQ Mode independent page 0 setup. */ | ||
629 | asd_write_reg_word(asd_ha, LmSEQ_Q_TGTXFR_HEAD(lseq), 0xFFFF); | ||
630 | asd_write_reg_word(asd_ha, LmSEQ_Q_TGTXFR_TAIL(lseq), 0xFFFF); | ||
631 | asd_write_reg_byte(asd_ha, LmSEQ_LINK_NUMBER(lseq), lseq); | ||
632 | asd_write_reg_byte(asd_ha, LmSEQ_SCRATCH_FLAGS(lseq), | ||
633 | ASD_NOTIFY_ENABLE_SPINUP); | ||
634 | asd_write_reg_dword(asd_ha, LmSEQ_CONNECTION_STATE(lseq),0x08000000); | ||
635 | asd_write_reg_word(asd_ha, LmSEQ_CONCTL(lseq), 0); | ||
636 | asd_write_reg_byte(asd_ha, LmSEQ_CONSTAT(lseq), 0); | ||
637 | asd_write_reg_byte(asd_ha, LmSEQ_CONNECTION_MODES(lseq), 0); | ||
638 | asd_write_reg_word(asd_ha, LmSEQ_REG1_ISR(lseq), 0); | ||
639 | asd_write_reg_word(asd_ha, LmSEQ_REG2_ISR(lseq), 0); | ||
640 | asd_write_reg_word(asd_ha, LmSEQ_REG3_ISR(lseq), 0); | ||
641 | asd_write_reg_dword(asd_ha, LmSEQ_REG0_ISR(lseq), 0); | ||
642 | asd_write_reg_dword(asd_ha, LmSEQ_REG0_ISR(lseq)+4, 0); | ||
643 | |||
644 | /* LSEQ Mode independent page 1 setup. */ | ||
645 | asd_write_reg_word(asd_ha, LmSEQ_EST_NEXUS_SCBPTR0(lseq), 0xFFFF); | ||
646 | asd_write_reg_word(asd_ha, LmSEQ_EST_NEXUS_SCBPTR1(lseq), 0xFFFF); | ||
647 | asd_write_reg_word(asd_ha, LmSEQ_EST_NEXUS_SCBPTR2(lseq), 0xFFFF); | ||
648 | asd_write_reg_word(asd_ha, LmSEQ_EST_NEXUS_SCBPTR3(lseq), 0xFFFF); | ||
649 | asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_OPCODE0(lseq), 0); | ||
650 | asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_OPCODE1(lseq), 0); | ||
651 | asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_OPCODE2(lseq), 0); | ||
652 | asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_OPCODE3(lseq), 0); | ||
653 | asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_HEAD(lseq), 0); | ||
654 | asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_TAIL(lseq), 0); | ||
655 | asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_BUF_AVAIL(lseq), 0); | ||
656 | asd_write_reg_dword(asd_ha, LmSEQ_TIMEOUT_CONST(lseq), 0); | ||
657 | asd_write_reg_word(asd_ha, LmSEQ_ISR_SAVE_SINDEX(lseq), 0); | ||
658 | asd_write_reg_word(asd_ha, LmSEQ_ISR_SAVE_DINDEX(lseq), 0); | ||
659 | |||
660 | /* LSEQ Mode Independent page 2 setup. */ | ||
661 | asd_write_reg_word(asd_ha, LmSEQ_EMPTY_SCB_PTR0(lseq), 0xFFFF); | ||
662 | asd_write_reg_word(asd_ha, LmSEQ_EMPTY_SCB_PTR1(lseq), 0xFFFF); | ||
663 | asd_write_reg_word(asd_ha, LmSEQ_EMPTY_SCB_PTR2(lseq), 0xFFFF); | ||
664 | asd_write_reg_word(asd_ha, LmSEQ_EMPTY_SCB_PTR3(lseq), 0xFFFF); | ||
665 | asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_OPCD0(lseq), 0); | ||
666 | asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_OPCD1(lseq), 0); | ||
667 | asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_OPCD2(lseq), 0); | ||
668 | asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_OPCD3(lseq), 0); | ||
669 | asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_HEAD(lseq), 0); | ||
670 | asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_TAIL(lseq), 0); | ||
671 | asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_BUFS_AVAIL(lseq), 0); | ||
672 | for (i = 0; i < 12; i += 4) | ||
673 | asd_write_reg_dword(asd_ha, LmSEQ_ATA_SCR_REGS(lseq) + i, 0); | ||
674 | |||
675 | /* LSEQ Mode Independent page 3 setup. */ | ||
676 | |||
677 | /* Device present timer timeout */ | ||
678 | asd_write_reg_dword(asd_ha, LmSEQ_DEV_PRES_TMR_TOUT_CONST(lseq), | ||
679 | ASD_DEV_PRESENT_TIMEOUT); | ||
680 | |||
681 | /* SATA interlock timer disabled */ | ||
682 | asd_write_reg_dword(asd_ha, LmSEQ_SATA_INTERLOCK_TIMEOUT(lseq), | ||
683 | ASD_SATA_INTERLOCK_TIMEOUT); | ||
684 | |||
685 | /* STP shutdown timer timeout constant, IGNORED by the sequencer, | ||
686 | * always 0. */ | ||
687 | asd_write_reg_dword(asd_ha, LmSEQ_STP_SHUTDOWN_TIMEOUT(lseq), | ||
688 | ASD_STP_SHUTDOWN_TIMEOUT); | ||
689 | |||
690 | asd_write_reg_dword(asd_ha, LmSEQ_SRST_ASSERT_TIMEOUT(lseq), | ||
691 | ASD_SRST_ASSERT_TIMEOUT); | ||
692 | |||
693 | asd_write_reg_dword(asd_ha, LmSEQ_RCV_FIS_TIMEOUT(lseq), | ||
694 | ASD_RCV_FIS_TIMEOUT); | ||
695 | |||
696 | asd_write_reg_dword(asd_ha, LmSEQ_ONE_MILLISEC_TIMEOUT(lseq), | ||
697 | ASD_ONE_MILLISEC_TIMEOUT); | ||
698 | |||
699 | /* COM_INIT timer */ | ||
700 | asd_write_reg_dword(asd_ha, LmSEQ_TEN_MS_COMINIT_TIMEOUT(lseq), | ||
701 | ASD_TEN_MILLISEC_TIMEOUT); | ||
702 | |||
703 | asd_write_reg_dword(asd_ha, LmSEQ_SMP_RCV_TIMEOUT(lseq), | ||
704 | ASD_SMP_RCV_TIMEOUT); | ||
705 | } | ||
706 | |||
707 | /** | ||
708 | * asd_init_lseq_mdp -- initialize LSEQ mode dependent pages. | ||
709 | * @asd_ha: pointer to host adapter structure | ||
710 | */ | ||
711 | static void asd_init_lseq_mdp(struct asd_ha_struct *asd_ha, int lseq) | ||
712 | { | ||
713 | int i; | ||
714 | u32 moffs; | ||
715 | u16 ret_addr[] = { | ||
716 | 0xFFFF, /* mode 0 */ | ||
717 | 0xFFFF, /* mode 1 */ | ||
718 | mode2_task, /* mode 2 */ | ||
719 | 0, | ||
720 | 0xFFFF, /* mode 4/5 */ | ||
721 | 0xFFFF, /* mode 4/5 */ | ||
722 | }; | ||
723 | |||
724 | /* | ||
725 | * Mode 0,1,2 and 4/5 have common field on page 0 for the first | ||
726 | * 14 bytes. | ||
727 | */ | ||
728 | for (i = 0; i < 3; i++) { | ||
729 | moffs = i * LSEQ_MODE_SCRATCH_SIZE; | ||
730 | asd_write_reg_word(asd_ha, LmSEQ_RET_ADDR(lseq)+moffs, | ||
731 | ret_addr[i]); | ||
732 | asd_write_reg_word(asd_ha, LmSEQ_REG0_MODE(lseq)+moffs, 0); | ||
733 | asd_write_reg_word(asd_ha, LmSEQ_MODE_FLAGS(lseq)+moffs, 0); | ||
734 | asd_write_reg_word(asd_ha, LmSEQ_RET_ADDR2(lseq)+moffs,0xFFFF); | ||
735 | asd_write_reg_word(asd_ha, LmSEQ_RET_ADDR1(lseq)+moffs,0xFFFF); | ||
736 | asd_write_reg_byte(asd_ha, LmSEQ_OPCODE_TO_CSEQ(lseq)+moffs,0); | ||
737 | asd_write_reg_word(asd_ha, LmSEQ_DATA_TO_CSEQ(lseq)+moffs,0); | ||
738 | } | ||
739 | /* | ||
740 | * Mode 5 page 0 overlaps the same scratch page with Mode 0 page 3. | ||
741 | */ | ||
742 | asd_write_reg_word(asd_ha, | ||
743 | LmSEQ_RET_ADDR(lseq)+LSEQ_MODE5_PAGE0_OFFSET, | ||
744 | ret_addr[5]); | ||
745 | asd_write_reg_word(asd_ha, | ||
746 | LmSEQ_REG0_MODE(lseq)+LSEQ_MODE5_PAGE0_OFFSET,0); | ||
747 | asd_write_reg_word(asd_ha, | ||
748 | LmSEQ_MODE_FLAGS(lseq)+LSEQ_MODE5_PAGE0_OFFSET, 0); | ||
749 | asd_write_reg_word(asd_ha, | ||
750 | LmSEQ_RET_ADDR2(lseq)+LSEQ_MODE5_PAGE0_OFFSET,0xFFFF); | ||
751 | asd_write_reg_word(asd_ha, | ||
752 | LmSEQ_RET_ADDR1(lseq)+LSEQ_MODE5_PAGE0_OFFSET,0xFFFF); | ||
753 | asd_write_reg_byte(asd_ha, | ||
754 | LmSEQ_OPCODE_TO_CSEQ(lseq)+LSEQ_MODE5_PAGE0_OFFSET,0); | ||
755 | asd_write_reg_word(asd_ha, | ||
756 | LmSEQ_DATA_TO_CSEQ(lseq)+LSEQ_MODE5_PAGE0_OFFSET, 0); | ||
757 | |||
758 | /* LSEQ Mode dependent 0, page 0 setup. */ | ||
759 | asd_write_reg_word(asd_ha, LmSEQ_FIRST_INV_DDB_SITE(lseq), | ||
760 | (u16)asd_ha->hw_prof.max_ddbs); | ||
761 | asd_write_reg_word(asd_ha, LmSEQ_EMPTY_TRANS_CTX(lseq), 0); | ||
762 | asd_write_reg_word(asd_ha, LmSEQ_RESP_LEN(lseq), 0); | ||
763 | asd_write_reg_word(asd_ha, LmSEQ_FIRST_INV_SCB_SITE(lseq), | ||
764 | (u16)last_scb_site_no+1); | ||
765 | asd_write_reg_word(asd_ha, LmSEQ_INTEN_SAVE(lseq), | ||
766 | (u16) LmM0INTEN_MASK & 0xFFFF0000 >> 16); | ||
767 | asd_write_reg_word(asd_ha, LmSEQ_INTEN_SAVE(lseq) + 2, | ||
768 | (u16) LmM0INTEN_MASK & 0xFFFF); | ||
769 | asd_write_reg_byte(asd_ha, LmSEQ_LINK_RST_FRM_LEN(lseq), 0); | ||
770 | asd_write_reg_byte(asd_ha, LmSEQ_LINK_RST_PROTOCOL(lseq), 0); | ||
771 | asd_write_reg_byte(asd_ha, LmSEQ_RESP_STATUS(lseq), 0); | ||
772 | asd_write_reg_byte(asd_ha, LmSEQ_LAST_LOADED_SGE(lseq), 0); | ||
773 | asd_write_reg_word(asd_ha, LmSEQ_SAVE_SCBPTR(lseq), 0); | ||
774 | |||
775 | /* LSEQ mode dependent, mode 1, page 0 setup. */ | ||
776 | asd_write_reg_word(asd_ha, LmSEQ_Q_XMIT_HEAD(lseq), 0xFFFF); | ||
777 | asd_write_reg_word(asd_ha, LmSEQ_M1_EMPTY_TRANS_CTX(lseq), 0); | ||
778 | asd_write_reg_word(asd_ha, LmSEQ_INI_CONN_TAG(lseq), 0); | ||
779 | asd_write_reg_byte(asd_ha, LmSEQ_FAILED_OPEN_STATUS(lseq), 0); | ||
780 | asd_write_reg_byte(asd_ha, LmSEQ_XMIT_REQUEST_TYPE(lseq), 0); | ||
781 | asd_write_reg_byte(asd_ha, LmSEQ_M1_RESP_STATUS(lseq), 0); | ||
782 | asd_write_reg_byte(asd_ha, LmSEQ_M1_LAST_LOADED_SGE(lseq), 0); | ||
783 | asd_write_reg_word(asd_ha, LmSEQ_M1_SAVE_SCBPTR(lseq), 0); | ||
784 | |||
785 | /* LSEQ Mode dependent mode 2, page 0 setup */ | ||
786 | asd_write_reg_word(asd_ha, LmSEQ_PORT_COUNTER(lseq), 0); | ||
787 | asd_write_reg_word(asd_ha, LmSEQ_PM_TABLE_PTR(lseq), 0); | ||
788 | asd_write_reg_word(asd_ha, LmSEQ_SATA_INTERLOCK_TMR_SAVE(lseq), 0); | ||
789 | asd_write_reg_word(asd_ha, LmSEQ_IP_BITL(lseq), 0); | ||
790 | asd_write_reg_word(asd_ha, LmSEQ_COPY_SMP_CONN_TAG(lseq), 0); | ||
791 | asd_write_reg_byte(asd_ha, LmSEQ_P0M2_OFFS1AH(lseq), 0); | ||
792 | |||
793 | /* LSEQ Mode dependent, mode 4/5, page 0 setup. */ | ||
794 | asd_write_reg_byte(asd_ha, LmSEQ_SAVED_OOB_STATUS(lseq), 0); | ||
795 | asd_write_reg_byte(asd_ha, LmSEQ_SAVED_OOB_MODE(lseq), 0); | ||
796 | asd_write_reg_word(asd_ha, LmSEQ_Q_LINK_HEAD(lseq), 0xFFFF); | ||
797 | asd_write_reg_byte(asd_ha, LmSEQ_LINK_RST_ERR(lseq), 0); | ||
798 | asd_write_reg_byte(asd_ha, LmSEQ_SAVED_OOB_SIGNALS(lseq), 0); | ||
799 | asd_write_reg_byte(asd_ha, LmSEQ_SAS_RESET_MODE(lseq), 0); | ||
800 | asd_write_reg_byte(asd_ha, LmSEQ_LINK_RESET_RETRY_COUNT(lseq), 0); | ||
801 | asd_write_reg_byte(asd_ha, LmSEQ_NUM_LINK_RESET_RETRIES(lseq), 0); | ||
802 | asd_write_reg_word(asd_ha, LmSEQ_OOB_INT_ENABLES(lseq), 0); | ||
803 | /* | ||
804 | * Set the desired interval between transmissions of the NOTIFY | ||
805 | * (ENABLE SPINUP) primitive. Must be initilized to val - 1. | ||
806 | */ | ||
807 | asd_write_reg_word(asd_ha, LmSEQ_NOTIFY_TIMER_TIMEOUT(lseq), | ||
808 | ASD_NOTIFY_TIMEOUT - 1); | ||
809 | /* No delay for the first NOTIFY to be sent to the attached target. */ | ||
810 | asd_write_reg_word(asd_ha, LmSEQ_NOTIFY_TIMER_DOWN_COUNT(lseq), | ||
811 | ASD_NOTIFY_DOWN_COUNT); | ||
812 | |||
813 | /* LSEQ Mode dependent, mode 0 and 1, page 1 setup. */ | ||
814 | for (i = 0; i < 2; i++) { | ||
815 | int j; | ||
816 | /* Start from Page 1 of Mode 0 and 1. */ | ||
817 | moffs = LSEQ_PAGE_SIZE + i*LSEQ_MODE_SCRATCH_SIZE; | ||
818 | /* All the fields of page 1 can be intialized to 0. */ | ||
819 | for (j = 0; j < LSEQ_PAGE_SIZE; j += 4) | ||
820 | asd_write_reg_dword(asd_ha, LmSCRATCH(lseq)+moffs+j,0); | ||
821 | } | ||
822 | |||
823 | /* LSEQ Mode dependent, mode 2, page 1 setup. */ | ||
824 | asd_write_reg_dword(asd_ha, LmSEQ_INVALID_DWORD_COUNT(lseq), 0); | ||
825 | asd_write_reg_dword(asd_ha, LmSEQ_DISPARITY_ERROR_COUNT(lseq), 0); | ||
826 | asd_write_reg_dword(asd_ha, LmSEQ_LOSS_OF_SYNC_COUNT(lseq), 0); | ||
827 | |||
828 | /* LSEQ Mode dependent, mode 4/5, page 1. */ | ||
829 | for (i = 0; i < LSEQ_PAGE_SIZE; i+=4) | ||
830 | asd_write_reg_dword(asd_ha, LmSEQ_FRAME_TYPE_MASK(lseq)+i, 0); | ||
831 | asd_write_reg_byte(asd_ha, LmSEQ_FRAME_TYPE_MASK(lseq), 0xFF); | ||
832 | asd_write_reg_byte(asd_ha, LmSEQ_HASHED_DEST_ADDR_MASK(lseq), 0xFF); | ||
833 | asd_write_reg_byte(asd_ha, LmSEQ_HASHED_DEST_ADDR_MASK(lseq)+1,0xFF); | ||
834 | asd_write_reg_byte(asd_ha, LmSEQ_HASHED_DEST_ADDR_MASK(lseq)+2,0xFF); | ||
835 | asd_write_reg_byte(asd_ha, LmSEQ_HASHED_SRC_ADDR_MASK(lseq), 0xFF); | ||
836 | asd_write_reg_byte(asd_ha, LmSEQ_HASHED_SRC_ADDR_MASK(lseq)+1, 0xFF); | ||
837 | asd_write_reg_byte(asd_ha, LmSEQ_HASHED_SRC_ADDR_MASK(lseq)+2, 0xFF); | ||
838 | asd_write_reg_dword(asd_ha, LmSEQ_DATA_OFFSET(lseq), 0xFFFFFFFF); | ||
839 | |||
840 | /* LSEQ Mode dependent, mode 0, page 2 setup. */ | ||
841 | asd_write_reg_dword(asd_ha, LmSEQ_SMP_RCV_TIMER_TERM_TS(lseq), 0); | ||
842 | asd_write_reg_byte(asd_ha, LmSEQ_DEVICE_BITS(lseq), 0); | ||
843 | asd_write_reg_word(asd_ha, LmSEQ_SDB_DDB(lseq), 0); | ||
844 | asd_write_reg_byte(asd_ha, LmSEQ_SDB_NUM_TAGS(lseq), 0); | ||
845 | asd_write_reg_byte(asd_ha, LmSEQ_SDB_CURR_TAG(lseq), 0); | ||
846 | |||
847 | /* LSEQ Mode Dependent 1, page 2 setup. */ | ||
848 | asd_write_reg_dword(asd_ha, LmSEQ_TX_ID_ADDR_FRAME(lseq), 0); | ||
849 | asd_write_reg_dword(asd_ha, LmSEQ_TX_ID_ADDR_FRAME(lseq)+4, 0); | ||
850 | asd_write_reg_dword(asd_ha, LmSEQ_OPEN_TIMER_TERM_TS(lseq), 0); | ||
851 | asd_write_reg_dword(asd_ha, LmSEQ_SRST_AS_TIMER_TERM_TS(lseq), 0); | ||
852 | asd_write_reg_dword(asd_ha, LmSEQ_LAST_LOADED_SG_EL(lseq), 0); | ||
853 | |||
854 | /* LSEQ Mode Dependent 2, page 2 setup. */ | ||
855 | /* The LmSEQ_STP_SHUTDOWN_TIMER_TERM_TS is IGNORED by the sequencer, | ||
856 | * i.e. always 0. */ | ||
857 | asd_write_reg_dword(asd_ha, LmSEQ_STP_SHUTDOWN_TIMER_TERM_TS(lseq),0); | ||
858 | asd_write_reg_dword(asd_ha, LmSEQ_CLOSE_TIMER_TERM_TS(lseq), 0); | ||
859 | asd_write_reg_dword(asd_ha, LmSEQ_BREAK_TIMER_TERM_TS(lseq), 0); | ||
860 | asd_write_reg_dword(asd_ha, LmSEQ_DWS_RESET_TIMER_TERM_TS(lseq), 0); | ||
861 | asd_write_reg_dword(asd_ha,LmSEQ_SATA_INTERLOCK_TIMER_TERM_TS(lseq),0); | ||
862 | asd_write_reg_dword(asd_ha, LmSEQ_MCTL_TIMER_TERM_TS(lseq), 0); | ||
863 | |||
864 | /* LSEQ Mode Dependent 4/5, page 2 setup. */ | ||
865 | asd_write_reg_dword(asd_ha, LmSEQ_COMINIT_TIMER_TERM_TS(lseq), 0); | ||
866 | asd_write_reg_dword(asd_ha, LmSEQ_RCV_ID_TIMER_TERM_TS(lseq), 0); | ||
867 | asd_write_reg_dword(asd_ha, LmSEQ_RCV_FIS_TIMER_TERM_TS(lseq), 0); | ||
868 | asd_write_reg_dword(asd_ha, LmSEQ_DEV_PRES_TIMER_TERM_TS(lseq), 0); | ||
869 | } | ||
870 | |||
871 | /** | ||
872 | * asd_init_lseq_scratch -- setup and init link sequencers | ||
873 | * @asd_ha: pointer to host adapter struct | ||
874 | */ | ||
875 | static void asd_init_lseq_scratch(struct asd_ha_struct *asd_ha) | ||
876 | { | ||
877 | u8 lseq; | ||
878 | u8 lseq_mask; | ||
879 | |||
880 | lseq_mask = asd_ha->hw_prof.enabled_phys; | ||
881 | for_each_sequencer(lseq_mask, lseq_mask, lseq) { | ||
882 | asd_init_lseq_mip(asd_ha, lseq); | ||
883 | asd_init_lseq_mdp(asd_ha, lseq); | ||
884 | } | ||
885 | } | ||
886 | |||
887 | /** | ||
888 | * asd_init_scb_sites -- initialize sequencer SCB sites (memory). | ||
889 | * @asd_ha: pointer to host adapter structure | ||
890 | * | ||
891 | * This should be done before initializing common CSEQ and LSEQ | ||
892 | * scratch since those areas depend on some computed values here, | ||
893 | * last_scb_site_no, etc. | ||
894 | */ | ||
895 | static void asd_init_scb_sites(struct asd_ha_struct *asd_ha) | ||
896 | { | ||
897 | u16 site_no; | ||
898 | u16 max_scbs = 0; | ||
899 | |||
900 | for (site_no = asd_ha->hw_prof.max_scbs-1; | ||
901 | site_no != (u16) -1; | ||
902 | site_no--) { | ||
903 | u16 i; | ||
904 | |||
905 | /* Initialize all fields in the SCB site to 0. */ | ||
906 | for (i = 0; i < ASD_SCB_SIZE; i += 4) | ||
907 | asd_scbsite_write_dword(asd_ha, site_no, i, 0); | ||
908 | |||
909 | /* Workaround needed by SEQ to fix a SATA issue is to exclude | ||
910 | * certain SCB sites from the free list. */ | ||
911 | if (!SCB_SITE_VALID(site_no)) | ||
912 | continue; | ||
913 | |||
914 | if (last_scb_site_no == 0) | ||
915 | last_scb_site_no = site_no; | ||
916 | |||
917 | /* For every SCB site, we need to initialize the | ||
918 | * following fields: Q_NEXT, SCB_OPCODE, SCB_FLAGS, | ||
919 | * and SG Element Flag. */ | ||
920 | |||
921 | /* Q_NEXT field of the last SCB is invalidated. */ | ||
922 | asd_scbsite_write_word(asd_ha, site_no, 0, first_scb_site_no); | ||
923 | |||
924 | /* Initialize SCB Site Opcode field to invalid. */ | ||
925 | asd_scbsite_write_byte(asd_ha, site_no, | ||
926 | offsetof(struct scb_header, opcode), | ||
927 | 0xFF); | ||
928 | |||
929 | /* Initialize SCB Site Flags field to mean a response | ||
930 | * frame has been received. This means inadvertent | ||
931 | * frames received to be dropped. */ | ||
932 | asd_scbsite_write_byte(asd_ha, site_no, 0x49, 0x01); | ||
933 | |||
934 | first_scb_site_no = site_no; | ||
935 | max_scbs++; | ||
936 | } | ||
937 | asd_ha->hw_prof.max_scbs = max_scbs; | ||
938 | ASD_DPRINTK("max_scbs:%d\n", asd_ha->hw_prof.max_scbs); | ||
939 | ASD_DPRINTK("first_scb_site_no:0x%x\n", first_scb_site_no); | ||
940 | ASD_DPRINTK("last_scb_site_no:0x%x\n", last_scb_site_no); | ||
941 | } | ||
942 | |||
943 | /** | ||
944 | * asd_init_cseq_cio - initialize CSEQ CIO registers | ||
945 | * @asd_ha: pointer to host adapter structure | ||
946 | */ | ||
947 | static void asd_init_cseq_cio(struct asd_ha_struct *asd_ha) | ||
948 | { | ||
949 | int i; | ||
950 | |||
951 | asd_write_reg_byte(asd_ha, CSEQCOMINTEN, 0); | ||
952 | asd_write_reg_byte(asd_ha, CSEQDLCTL, ASD_DL_SIZE_BITS); | ||
953 | asd_write_reg_byte(asd_ha, CSEQDLOFFS, 0); | ||
954 | asd_write_reg_byte(asd_ha, CSEQDLOFFS+1, 0); | ||
955 | asd_ha->seq.scbpro = 0; | ||
956 | asd_write_reg_dword(asd_ha, SCBPRO, 0); | ||
957 | asd_write_reg_dword(asd_ha, CSEQCON, 0); | ||
958 | |||
959 | /* Intialize CSEQ Mode 11 Interrupt Vectors. | ||
960 | * The addresses are 16 bit wide and in dword units. | ||
961 | * The values of their macros are in byte units. | ||
962 | * Thus we have to divide by 4. */ | ||
963 | asd_write_reg_word(asd_ha, CM11INTVEC0, cseq_vecs[0]); | ||
964 | asd_write_reg_word(asd_ha, CM11INTVEC1, cseq_vecs[1]); | ||
965 | asd_write_reg_word(asd_ha, CM11INTVEC2, cseq_vecs[2]); | ||
966 | |||
967 | /* Enable ARP2HALTC (ARP2 Halted from Halt Code Write). */ | ||
968 | asd_write_reg_byte(asd_ha, CARP2INTEN, EN_ARP2HALTC); | ||
969 | |||
970 | /* Initialize CSEQ Scratch Page to 0x04. */ | ||
971 | asd_write_reg_byte(asd_ha, CSCRATCHPAGE, 0x04); | ||
972 | |||
973 | /* Initialize CSEQ Mode[0-8] Dependent registers. */ | ||
974 | /* Initialize Scratch Page to 0. */ | ||
975 | for (i = 0; i < 9; i++) | ||
976 | asd_write_reg_byte(asd_ha, CMnSCRATCHPAGE(i), 0); | ||
977 | |||
978 | /* Reset the ARP2 Program Count. */ | ||
979 | asd_write_reg_word(asd_ha, CPRGMCNT, cseq_idle_loop); | ||
980 | |||
981 | for (i = 0; i < 8; i++) { | ||
982 | /* Intialize Mode n Link m Interrupt Enable. */ | ||
983 | asd_write_reg_dword(asd_ha, CMnINTEN(i), EN_CMnRSPMBXF); | ||
984 | /* Initialize Mode n Request Mailbox. */ | ||
985 | asd_write_reg_dword(asd_ha, CMnREQMBX(i), 0); | ||
986 | } | ||
987 | } | ||
988 | |||
989 | /** | ||
990 | * asd_init_lseq_cio -- initialize LmSEQ CIO registers | ||
991 | * @asd_ha: pointer to host adapter structure | ||
992 | */ | ||
993 | static void asd_init_lseq_cio(struct asd_ha_struct *asd_ha, int lseq) | ||
994 | { | ||
995 | u8 *sas_addr; | ||
996 | int i; | ||
997 | |||
998 | /* Enable ARP2HALTC (ARP2 Halted from Halt Code Write). */ | ||
999 | asd_write_reg_dword(asd_ha, LmARP2INTEN(lseq), EN_ARP2HALTC); | ||
1000 | |||
1001 | asd_write_reg_byte(asd_ha, LmSCRATCHPAGE(lseq), 0); | ||
1002 | |||
1003 | /* Initialize Mode 0,1, and 2 SCRATCHPAGE to 0. */ | ||
1004 | for (i = 0; i < 3; i++) | ||
1005 | asd_write_reg_byte(asd_ha, LmMnSCRATCHPAGE(lseq, i), 0); | ||
1006 | |||
1007 | /* Initialize Mode 5 SCRATCHPAGE to 0. */ | ||
1008 | asd_write_reg_byte(asd_ha, LmMnSCRATCHPAGE(lseq, 5), 0); | ||
1009 | |||
1010 | asd_write_reg_dword(asd_ha, LmRSPMBX(lseq), 0); | ||
1011 | /* Initialize Mode 0,1,2 and 5 Interrupt Enable and | ||
1012 | * Interrupt registers. */ | ||
1013 | asd_write_reg_dword(asd_ha, LmMnINTEN(lseq, 0), LmM0INTEN_MASK); | ||
1014 | asd_write_reg_dword(asd_ha, LmMnINT(lseq, 0), 0xFFFFFFFF); | ||
1015 | /* Mode 1 */ | ||
1016 | asd_write_reg_dword(asd_ha, LmMnINTEN(lseq, 1), LmM1INTEN_MASK); | ||
1017 | asd_write_reg_dword(asd_ha, LmMnINT(lseq, 1), 0xFFFFFFFF); | ||
1018 | /* Mode 2 */ | ||
1019 | asd_write_reg_dword(asd_ha, LmMnINTEN(lseq, 2), LmM2INTEN_MASK); | ||
1020 | asd_write_reg_dword(asd_ha, LmMnINT(lseq, 2), 0xFFFFFFFF); | ||
1021 | /* Mode 5 */ | ||
1022 | asd_write_reg_dword(asd_ha, LmMnINTEN(lseq, 5), LmM5INTEN_MASK); | ||
1023 | asd_write_reg_dword(asd_ha, LmMnINT(lseq, 5), 0xFFFFFFFF); | ||
1024 | |||
1025 | /* Enable HW Timer status. */ | ||
1026 | asd_write_reg_byte(asd_ha, LmHWTSTATEN(lseq), LmHWTSTATEN_MASK); | ||
1027 | |||
1028 | /* Enable Primitive Status 0 and 1. */ | ||
1029 | asd_write_reg_dword(asd_ha, LmPRIMSTAT0EN(lseq), LmPRIMSTAT0EN_MASK); | ||
1030 | asd_write_reg_dword(asd_ha, LmPRIMSTAT1EN(lseq), LmPRIMSTAT1EN_MASK); | ||
1031 | |||
1032 | /* Enable Frame Error. */ | ||
1033 | asd_write_reg_dword(asd_ha, LmFRMERREN(lseq), LmFRMERREN_MASK); | ||
1034 | asd_write_reg_byte(asd_ha, LmMnHOLDLVL(lseq, 0), 0x50); | ||
1035 | |||
1036 | /* Initialize Mode 0 Transfer Level to 512. */ | ||
1037 | asd_write_reg_byte(asd_ha, LmMnXFRLVL(lseq, 0), LmMnXFRLVL_512); | ||
1038 | /* Initialize Mode 1 Transfer Level to 256. */ | ||
1039 | asd_write_reg_byte(asd_ha, LmMnXFRLVL(lseq, 1), LmMnXFRLVL_256); | ||
1040 | |||
1041 | /* Initialize Program Count. */ | ||
1042 | asd_write_reg_word(asd_ha, LmPRGMCNT(lseq), lseq_idle_loop); | ||
1043 | |||
1044 | /* Enable Blind SG Move. */ | ||
1045 | asd_write_reg_dword(asd_ha, LmMODECTL(lseq), LmBLIND48); | ||
1046 | asd_write_reg_word(asd_ha, LmM3SATATIMER(lseq), | ||
1047 | ASD_SATA_INTERLOCK_TIMEOUT); | ||
1048 | |||
1049 | (void) asd_read_reg_dword(asd_ha, LmREQMBX(lseq)); | ||
1050 | |||
1051 | /* Clear Primitive Status 0 and 1. */ | ||
1052 | asd_write_reg_dword(asd_ha, LmPRMSTAT0(lseq), 0xFFFFFFFF); | ||
1053 | asd_write_reg_dword(asd_ha, LmPRMSTAT1(lseq), 0xFFFFFFFF); | ||
1054 | |||
1055 | /* Clear HW Timer status. */ | ||
1056 | asd_write_reg_byte(asd_ha, LmHWTSTAT(lseq), 0xFF); | ||
1057 | |||
1058 | /* Clear DMA Errors for Mode 0 and 1. */ | ||
1059 | asd_write_reg_byte(asd_ha, LmMnDMAERRS(lseq, 0), 0xFF); | ||
1060 | asd_write_reg_byte(asd_ha, LmMnDMAERRS(lseq, 1), 0xFF); | ||
1061 | |||
1062 | /* Clear SG DMA Errors for Mode 0 and 1. */ | ||
1063 | asd_write_reg_byte(asd_ha, LmMnSGDMAERRS(lseq, 0), 0xFF); | ||
1064 | asd_write_reg_byte(asd_ha, LmMnSGDMAERRS(lseq, 1), 0xFF); | ||
1065 | |||
1066 | /* Clear Mode 0 Buffer Parity Error. */ | ||
1067 | asd_write_reg_byte(asd_ha, LmMnBUFSTAT(lseq, 0), LmMnBUFPERR); | ||
1068 | |||
1069 | /* Clear Mode 0 Frame Error register. */ | ||
1070 | asd_write_reg_dword(asd_ha, LmMnFRMERR(lseq, 0), 0xFFFFFFFF); | ||
1071 | |||
1072 | /* Reset LSEQ external interrupt arbiter. */ | ||
1073 | asd_write_reg_byte(asd_ha, LmARP2INTCTL(lseq), RSTINTCTL); | ||
1074 | |||
1075 | /* Set the Phy SAS for the LmSEQ WWN. */ | ||
1076 | sas_addr = asd_ha->phys[lseq].phy_desc->sas_addr; | ||
1077 | for (i = 0; i < SAS_ADDR_SIZE; i++) | ||
1078 | asd_write_reg_byte(asd_ha, LmWWN(lseq) + i, sas_addr[i]); | ||
1079 | |||
1080 | /* Set the Transmit Size to 1024 bytes, 0 = 256 Dwords. */ | ||
1081 | asd_write_reg_byte(asd_ha, LmMnXMTSIZE(lseq, 1), 0); | ||
1082 | |||
1083 | /* Set the Bus Inactivity Time Limit Timer. */ | ||
1084 | asd_write_reg_word(asd_ha, LmBITL_TIMER(lseq), 9); | ||
1085 | |||
1086 | /* Enable SATA Port Multiplier. */ | ||
1087 | asd_write_reg_byte(asd_ha, LmMnSATAFS(lseq, 1), 0x80); | ||
1088 | |||
1089 | /* Initialize Interrupt Vector[0-10] address in Mode 3. | ||
1090 | * See the comment on CSEQ_INT_* */ | ||
1091 | asd_write_reg_word(asd_ha, LmM3INTVEC0(lseq), lseq_vecs[0]); | ||
1092 | asd_write_reg_word(asd_ha, LmM3INTVEC1(lseq), lseq_vecs[1]); | ||
1093 | asd_write_reg_word(asd_ha, LmM3INTVEC2(lseq), lseq_vecs[2]); | ||
1094 | asd_write_reg_word(asd_ha, LmM3INTVEC3(lseq), lseq_vecs[3]); | ||
1095 | asd_write_reg_word(asd_ha, LmM3INTVEC4(lseq), lseq_vecs[4]); | ||
1096 | asd_write_reg_word(asd_ha, LmM3INTVEC5(lseq), lseq_vecs[5]); | ||
1097 | asd_write_reg_word(asd_ha, LmM3INTVEC6(lseq), lseq_vecs[6]); | ||
1098 | asd_write_reg_word(asd_ha, LmM3INTVEC7(lseq), lseq_vecs[7]); | ||
1099 | asd_write_reg_word(asd_ha, LmM3INTVEC8(lseq), lseq_vecs[8]); | ||
1100 | asd_write_reg_word(asd_ha, LmM3INTVEC9(lseq), lseq_vecs[9]); | ||
1101 | asd_write_reg_word(asd_ha, LmM3INTVEC10(lseq), lseq_vecs[10]); | ||
1102 | /* | ||
1103 | * Program the Link LED control, applicable only for | ||
1104 | * Chip Rev. B or later. | ||
1105 | */ | ||
1106 | asd_write_reg_dword(asd_ha, LmCONTROL(lseq), | ||
1107 | (LEDTIMER | LEDMODE_TXRX | LEDTIMERS_100ms)); | ||
1108 | |||
1109 | /* Set the Align Rate for SAS and STP mode. */ | ||
1110 | asd_write_reg_byte(asd_ha, LmM1SASALIGN(lseq), SAS_ALIGN_DEFAULT); | ||
1111 | asd_write_reg_byte(asd_ha, LmM1STPALIGN(lseq), STP_ALIGN_DEFAULT); | ||
1112 | } | ||
1113 | |||
1114 | |||
1115 | /** | ||
1116 | * asd_post_init_cseq -- clear CSEQ Mode n Int. status and Response mailbox | ||
1117 | * @asd_ha: pointer to host adapter struct | ||
1118 | */ | ||
1119 | static void asd_post_init_cseq(struct asd_ha_struct *asd_ha) | ||
1120 | { | ||
1121 | int i; | ||
1122 | |||
1123 | for (i = 0; i < 8; i++) | ||
1124 | asd_write_reg_dword(asd_ha, CMnINT(i), 0xFFFFFFFF); | ||
1125 | for (i = 0; i < 8; i++) | ||
1126 | asd_read_reg_dword(asd_ha, CMnRSPMBX(i)); | ||
1127 | /* Reset the external interrupt arbiter. */ | ||
1128 | asd_write_reg_byte(asd_ha, CARP2INTCTL, RSTINTCTL); | ||
1129 | } | ||
1130 | |||
1131 | /** | ||
1132 | * asd_init_ddb_0 -- initialize DDB 0 | ||
1133 | * @asd_ha: pointer to host adapter structure | ||
1134 | * | ||
1135 | * Initialize DDB site 0 which is used internally by the sequencer. | ||
1136 | */ | ||
1137 | static void asd_init_ddb_0(struct asd_ha_struct *asd_ha) | ||
1138 | { | ||
1139 | int i; | ||
1140 | |||
1141 | /* Zero out the DDB explicitly */ | ||
1142 | for (i = 0; i < sizeof(struct asd_ddb_seq_shared); i+=4) | ||
1143 | asd_ddbsite_write_dword(asd_ha, 0, i, 0); | ||
1144 | |||
1145 | asd_ddbsite_write_word(asd_ha, 0, | ||
1146 | offsetof(struct asd_ddb_seq_shared, q_free_ddb_head), 0); | ||
1147 | asd_ddbsite_write_word(asd_ha, 0, | ||
1148 | offsetof(struct asd_ddb_seq_shared, q_free_ddb_tail), | ||
1149 | asd_ha->hw_prof.max_ddbs-1); | ||
1150 | asd_ddbsite_write_word(asd_ha, 0, | ||
1151 | offsetof(struct asd_ddb_seq_shared, q_free_ddb_cnt), 0); | ||
1152 | asd_ddbsite_write_word(asd_ha, 0, | ||
1153 | offsetof(struct asd_ddb_seq_shared, q_used_ddb_head), 0xFFFF); | ||
1154 | asd_ddbsite_write_word(asd_ha, 0, | ||
1155 | offsetof(struct asd_ddb_seq_shared, q_used_ddb_tail), 0xFFFF); | ||
1156 | asd_ddbsite_write_word(asd_ha, 0, | ||
1157 | offsetof(struct asd_ddb_seq_shared, shared_mem_lock), 0); | ||
1158 | asd_ddbsite_write_word(asd_ha, 0, | ||
1159 | offsetof(struct asd_ddb_seq_shared, smp_conn_tag), 0); | ||
1160 | asd_ddbsite_write_word(asd_ha, 0, | ||
1161 | offsetof(struct asd_ddb_seq_shared, est_nexus_buf_cnt), 0); | ||
1162 | asd_ddbsite_write_word(asd_ha, 0, | ||
1163 | offsetof(struct asd_ddb_seq_shared, est_nexus_buf_thresh), | ||
1164 | asd_ha->hw_prof.num_phys * 2); | ||
1165 | asd_ddbsite_write_byte(asd_ha, 0, | ||
1166 | offsetof(struct asd_ddb_seq_shared, settable_max_contexts),0); | ||
1167 | asd_ddbsite_write_byte(asd_ha, 0, | ||
1168 | offsetof(struct asd_ddb_seq_shared, conn_not_active), 0xFF); | ||
1169 | asd_ddbsite_write_byte(asd_ha, 0, | ||
1170 | offsetof(struct asd_ddb_seq_shared, phy_is_up), 0x00); | ||
1171 | /* DDB 0 is reserved */ | ||
1172 | set_bit(0, asd_ha->hw_prof.ddb_bitmap); | ||
1173 | } | ||
1174 | |||
1175 | /** | ||
1176 | * asd_seq_setup_seqs -- setup and initialize central and link sequencers | ||
1177 | * @asd_ha: pointer to host adapter structure | ||
1178 | */ | ||
1179 | static void asd_seq_setup_seqs(struct asd_ha_struct *asd_ha) | ||
1180 | { | ||
1181 | int lseq; | ||
1182 | u8 lseq_mask; | ||
1183 | |||
1184 | /* Initialize SCB sites. Done first to compute some values which | ||
1185 | * the rest of the init code depends on. */ | ||
1186 | asd_init_scb_sites(asd_ha); | ||
1187 | |||
1188 | /* Initialize CSEQ Scratch RAM registers. */ | ||
1189 | asd_init_cseq_scratch(asd_ha); | ||
1190 | |||
1191 | /* Initialize LmSEQ Scratch RAM registers. */ | ||
1192 | asd_init_lseq_scratch(asd_ha); | ||
1193 | |||
1194 | /* Initialize CSEQ CIO registers. */ | ||
1195 | asd_init_cseq_cio(asd_ha); | ||
1196 | |||
1197 | asd_init_ddb_0(asd_ha); | ||
1198 | |||
1199 | /* Initialize LmSEQ CIO registers. */ | ||
1200 | lseq_mask = asd_ha->hw_prof.enabled_phys; | ||
1201 | for_each_sequencer(lseq_mask, lseq_mask, lseq) | ||
1202 | asd_init_lseq_cio(asd_ha, lseq); | ||
1203 | asd_post_init_cseq(asd_ha); | ||
1204 | } | ||
1205 | |||
1206 | |||
1207 | /** | ||
1208 | * asd_seq_start_cseq -- start the central sequencer, CSEQ | ||
1209 | * @asd_ha: pointer to host adapter structure | ||
1210 | */ | ||
1211 | static int asd_seq_start_cseq(struct asd_ha_struct *asd_ha) | ||
1212 | { | ||
1213 | /* Reset the ARP2 instruction to location zero. */ | ||
1214 | asd_write_reg_word(asd_ha, CPRGMCNT, cseq_idle_loop); | ||
1215 | |||
1216 | /* Unpause the CSEQ */ | ||
1217 | return asd_unpause_cseq(asd_ha); | ||
1218 | } | ||
1219 | |||
1220 | /** | ||
1221 | * asd_seq_start_lseq -- start a link sequencer | ||
1222 | * @asd_ha: pointer to host adapter structure | ||
1223 | * @lseq: the link sequencer of interest | ||
1224 | */ | ||
1225 | static int asd_seq_start_lseq(struct asd_ha_struct *asd_ha, int lseq) | ||
1226 | { | ||
1227 | /* Reset the ARP2 instruction to location zero. */ | ||
1228 | asd_write_reg_word(asd_ha, LmPRGMCNT(lseq), lseq_idle_loop); | ||
1229 | |||
1230 | /* Unpause the LmSEQ */ | ||
1231 | return asd_seq_unpause_lseq(asd_ha, lseq); | ||
1232 | } | ||
1233 | |||
1234 | static int asd_request_firmware(struct asd_ha_struct *asd_ha) | ||
1235 | { | ||
1236 | int err, i; | ||
1237 | struct sequencer_file_header header, *hdr_ptr; | ||
1238 | u32 csum = 0; | ||
1239 | u16 *ptr_cseq_vecs, *ptr_lseq_vecs; | ||
1240 | |||
1241 | if (sequencer_fw) | ||
1242 | /* already loaded */ | ||
1243 | return 0; | ||
1244 | |||
1245 | err = request_firmware(&sequencer_fw, | ||
1246 | SAS_RAZOR_SEQUENCER_FW_FILE, | ||
1247 | &asd_ha->pcidev->dev); | ||
1248 | if (err) | ||
1249 | return err; | ||
1250 | |||
1251 | hdr_ptr = (struct sequencer_file_header *)sequencer_fw->data; | ||
1252 | |||
1253 | header.csum = le32_to_cpu(hdr_ptr->csum); | ||
1254 | header.major = le32_to_cpu(hdr_ptr->major); | ||
1255 | header.minor = le32_to_cpu(hdr_ptr->minor); | ||
1256 | sequencer_version = hdr_ptr->version; | ||
1257 | header.cseq_table_offset = le32_to_cpu(hdr_ptr->cseq_table_offset); | ||
1258 | header.cseq_table_size = le32_to_cpu(hdr_ptr->cseq_table_size); | ||
1259 | header.lseq_table_offset = le32_to_cpu(hdr_ptr->lseq_table_offset); | ||
1260 | header.lseq_table_size = le32_to_cpu(hdr_ptr->lseq_table_size); | ||
1261 | header.cseq_code_offset = le32_to_cpu(hdr_ptr->cseq_code_offset); | ||
1262 | header.cseq_code_size = le32_to_cpu(hdr_ptr->cseq_code_size); | ||
1263 | header.lseq_code_offset = le32_to_cpu(hdr_ptr->lseq_code_offset); | ||
1264 | header.lseq_code_size = le32_to_cpu(hdr_ptr->lseq_code_size); | ||
1265 | header.mode2_task = le16_to_cpu(hdr_ptr->mode2_task); | ||
1266 | header.cseq_idle_loop = le16_to_cpu(hdr_ptr->cseq_idle_loop); | ||
1267 | header.lseq_idle_loop = le16_to_cpu(hdr_ptr->lseq_idle_loop); | ||
1268 | |||
1269 | for (i = sizeof(header.csum); i < sequencer_fw->size; i++) | ||
1270 | csum += sequencer_fw->data[i]; | ||
1271 | |||
1272 | if (csum != header.csum) { | ||
1273 | asd_printk("Firmware file checksum mismatch\n"); | ||
1274 | return -EINVAL; | ||
1275 | } | ||
1276 | |||
1277 | if (header.cseq_table_size != CSEQ_NUM_VECS || | ||
1278 | header.lseq_table_size != LSEQ_NUM_VECS) { | ||
1279 | asd_printk("Firmware file table size mismatch\n"); | ||
1280 | return -EINVAL; | ||
1281 | } | ||
1282 | |||
1283 | ptr_cseq_vecs = (u16 *)&sequencer_fw->data[header.cseq_table_offset]; | ||
1284 | ptr_lseq_vecs = (u16 *)&sequencer_fw->data[header.lseq_table_offset]; | ||
1285 | mode2_task = header.mode2_task; | ||
1286 | cseq_idle_loop = header.cseq_idle_loop; | ||
1287 | lseq_idle_loop = header.lseq_idle_loop; | ||
1288 | |||
1289 | for (i = 0; i < CSEQ_NUM_VECS; i++) | ||
1290 | cseq_vecs[i] = le16_to_cpu(ptr_cseq_vecs[i]); | ||
1291 | |||
1292 | for (i = 0; i < LSEQ_NUM_VECS; i++) | ||
1293 | lseq_vecs[i] = le16_to_cpu(ptr_lseq_vecs[i]); | ||
1294 | |||
1295 | cseq_code = &sequencer_fw->data[header.cseq_code_offset]; | ||
1296 | cseq_code_size = header.cseq_code_size; | ||
1297 | lseq_code = &sequencer_fw->data[header.lseq_code_offset]; | ||
1298 | lseq_code_size = header.lseq_code_size; | ||
1299 | |||
1300 | return 0; | ||
1301 | } | ||
1302 | |||
1303 | int asd_init_seqs(struct asd_ha_struct *asd_ha) | ||
1304 | { | ||
1305 | int err; | ||
1306 | |||
1307 | err = asd_request_firmware(asd_ha); | ||
1308 | |||
1309 | if (err) { | ||
1310 | asd_printk("Failed to load sequencer firmware file %s, error %d\n", | ||
1311 | SAS_RAZOR_SEQUENCER_FW_FILE, err); | ||
1312 | return err; | ||
1313 | } | ||
1314 | |||
1315 | asd_printk("using sequencer %s\n", sequencer_version); | ||
1316 | err = asd_seq_download_seqs(asd_ha); | ||
1317 | if (err) { | ||
1318 | asd_printk("couldn't download sequencers for %s\n", | ||
1319 | pci_name(asd_ha->pcidev)); | ||
1320 | return err; | ||
1321 | } | ||
1322 | |||
1323 | asd_seq_setup_seqs(asd_ha); | ||
1324 | |||
1325 | return 0; | ||
1326 | } | ||
1327 | |||
1328 | int asd_start_seqs(struct asd_ha_struct *asd_ha) | ||
1329 | { | ||
1330 | int err; | ||
1331 | u8 lseq_mask; | ||
1332 | int lseq; | ||
1333 | |||
1334 | err = asd_seq_start_cseq(asd_ha); | ||
1335 | if (err) { | ||
1336 | asd_printk("couldn't start CSEQ for %s\n", | ||
1337 | pci_name(asd_ha->pcidev)); | ||
1338 | return err; | ||
1339 | } | ||
1340 | |||
1341 | lseq_mask = asd_ha->hw_prof.enabled_phys; | ||
1342 | for_each_sequencer(lseq_mask, lseq_mask, lseq) { | ||
1343 | err = asd_seq_start_lseq(asd_ha, lseq); | ||
1344 | if (err) { | ||
1345 | asd_printk("coudln't start LSEQ %d for %s\n", lseq, | ||
1346 | pci_name(asd_ha->pcidev)); | ||
1347 | return err; | ||
1348 | } | ||
1349 | } | ||
1350 | |||
1351 | return 0; | ||
1352 | } | ||
1353 | |||
1354 | /** | ||
1355 | * asd_update_port_links -- update port_map_by_links and phy_is_up | ||
1356 | * @sas_phy: pointer to the phy which has been added to a port | ||
1357 | * | ||
1358 | * 1) When a link reset has completed and we got BYTES DMAED with a | ||
1359 | * valid frame we call this function for that phy, to indicate that | ||
1360 | * the phy is up, i.e. we update the phy_is_up in DDB 0. The | ||
1361 | * sequencer checks phy_is_up when pending SCBs are to be sent, and | ||
1362 | * when an open address frame has been received. | ||
1363 | * | ||
1364 | * 2) When we know of ports, we call this function to update the map | ||
1365 | * of phys participaing in that port, i.e. we update the | ||
1366 | * port_map_by_links in DDB 0. When a HARD_RESET primitive has been | ||
1367 | * received, the sequencer disables all phys in that port. | ||
1368 | * port_map_by_links is also used as the conn_mask byte in the | ||
1369 | * initiator/target port DDB. | ||
1370 | */ | ||
1371 | void asd_update_port_links(struct asd_sas_phy *sas_phy) | ||
1372 | { | ||
1373 | struct asd_ha_struct *asd_ha = sas_phy->ha->lldd_ha; | ||
1374 | const u8 phy_mask = (u8) sas_phy->port->phy_mask; | ||
1375 | u8 phy_is_up; | ||
1376 | u8 mask; | ||
1377 | int i, err; | ||
1378 | |||
1379 | for_each_phy(phy_mask, mask, i) | ||
1380 | asd_ddbsite_write_byte(asd_ha, 0, | ||
1381 | offsetof(struct asd_ddb_seq_shared, | ||
1382 | port_map_by_links)+i,phy_mask); | ||
1383 | |||
1384 | for (i = 0; i < 12; i++) { | ||
1385 | phy_is_up = asd_ddbsite_read_byte(asd_ha, 0, | ||
1386 | offsetof(struct asd_ddb_seq_shared, phy_is_up)); | ||
1387 | err = asd_ddbsite_update_byte(asd_ha, 0, | ||
1388 | offsetof(struct asd_ddb_seq_shared, phy_is_up), | ||
1389 | phy_is_up, | ||
1390 | phy_is_up | phy_mask); | ||
1391 | if (!err) | ||
1392 | break; | ||
1393 | else if (err == -EFAULT) { | ||
1394 | asd_printk("phy_is_up: parity error in DDB 0\n"); | ||
1395 | break; | ||
1396 | } | ||
1397 | } | ||
1398 | |||
1399 | if (err) | ||
1400 | asd_printk("couldn't update DDB 0:error:%d\n", err); | ||
1401 | } | ||
diff --git a/drivers/scsi/aic94xx/aic94xx_seq.h b/drivers/scsi/aic94xx/aic94xx_seq.h new file mode 100644 index 000000000000..42281c36153b --- /dev/null +++ b/drivers/scsi/aic94xx/aic94xx_seq.h | |||
@@ -0,0 +1,70 @@ | |||
1 | /* | ||
2 | * Aic94xx SAS/SATA driver sequencer interface header file. | ||
3 | * | ||
4 | * Copyright (C) 2005 Adaptec, Inc. All rights reserved. | ||
5 | * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> | ||
6 | * | ||
7 | * This file is licensed under GPLv2. | ||
8 | * | ||
9 | * This file is part of the aic94xx driver. | ||
10 | * | ||
11 | * The aic94xx driver is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License as | ||
13 | * published by the Free Software Foundation; version 2 of the | ||
14 | * License. | ||
15 | * | ||
16 | * The aic94xx driver is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
19 | * General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with the aic94xx driver; if not, write to the Free Software | ||
23 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #ifndef _AIC94XX_SEQ_H_ | ||
28 | #define _AIC94XX_SEQ_H_ | ||
29 | |||
30 | #define CSEQ_NUM_VECS 3 | ||
31 | #define LSEQ_NUM_VECS 11 | ||
32 | |||
33 | #define SAS_RAZOR_SEQUENCER_FW_FILE "aic94xx-seq.fw" | ||
34 | |||
35 | /* Note: All quantites in the sequencer file are little endian */ | ||
36 | struct sequencer_file_header { | ||
37 | /* Checksum of the entire contents of the sequencer excluding | ||
38 | * these four bytes */ | ||
39 | u32 csum; | ||
40 | /* numeric major version */ | ||
41 | u32 major; | ||
42 | /* numeric minor version */ | ||
43 | u32 minor; | ||
44 | /* version string printed by driver */ | ||
45 | char version[16]; | ||
46 | u32 cseq_table_offset; | ||
47 | u32 cseq_table_size; | ||
48 | u32 lseq_table_offset; | ||
49 | u32 lseq_table_size; | ||
50 | u32 cseq_code_offset; | ||
51 | u32 cseq_code_size; | ||
52 | u32 lseq_code_offset; | ||
53 | u32 lseq_code_size; | ||
54 | u16 mode2_task; | ||
55 | u16 cseq_idle_loop; | ||
56 | u16 lseq_idle_loop; | ||
57 | } __attribute__((packed)); | ||
58 | |||
59 | #ifdef __KERNEL__ | ||
60 | int asd_pause_cseq(struct asd_ha_struct *asd_ha); | ||
61 | int asd_unpause_cseq(struct asd_ha_struct *asd_ha); | ||
62 | int asd_pause_lseq(struct asd_ha_struct *asd_ha, u8 lseq_mask); | ||
63 | int asd_unpause_lseq(struct asd_ha_struct *asd_ha, u8 lseq_mask); | ||
64 | int asd_init_seqs(struct asd_ha_struct *asd_ha); | ||
65 | int asd_start_seqs(struct asd_ha_struct *asd_ha); | ||
66 | |||
67 | void asd_update_port_links(struct asd_sas_phy *phy); | ||
68 | #endif | ||
69 | |||
70 | #endif | ||
diff --git a/drivers/scsi/aic94xx/aic94xx_task.c b/drivers/scsi/aic94xx/aic94xx_task.c new file mode 100644 index 000000000000..285e70dae933 --- /dev/null +++ b/drivers/scsi/aic94xx/aic94xx_task.c | |||
@@ -0,0 +1,642 @@ | |||
1 | /* | ||
2 | * Aic94xx SAS/SATA Tasks | ||
3 | * | ||
4 | * Copyright (C) 2005 Adaptec, Inc. All rights reserved. | ||
5 | * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> | ||
6 | * | ||
7 | * This file is licensed under GPLv2. | ||
8 | * | ||
9 | * This file is part of the aic94xx driver. | ||
10 | * | ||
11 | * The aic94xx driver is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License as | ||
13 | * published by the Free Software Foundation; version 2 of the | ||
14 | * License. | ||
15 | * | ||
16 | * The aic94xx driver is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
19 | * General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with the aic94xx driver; if not, write to the Free Software | ||
23 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #include <linux/spinlock.h> | ||
28 | #include "aic94xx.h" | ||
29 | #include "aic94xx_sas.h" | ||
30 | #include "aic94xx_hwi.h" | ||
31 | |||
32 | static void asd_unbuild_ata_ascb(struct asd_ascb *a); | ||
33 | static void asd_unbuild_smp_ascb(struct asd_ascb *a); | ||
34 | static void asd_unbuild_ssp_ascb(struct asd_ascb *a); | ||
35 | |||
36 | static inline void asd_can_dequeue(struct asd_ha_struct *asd_ha, int num) | ||
37 | { | ||
38 | unsigned long flags; | ||
39 | |||
40 | spin_lock_irqsave(&asd_ha->seq.pend_q_lock, flags); | ||
41 | asd_ha->seq.can_queue += num; | ||
42 | spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags); | ||
43 | } | ||
44 | |||
45 | /* PCI_DMA_... to our direction translation. | ||
46 | */ | ||
47 | static const u8 data_dir_flags[] = { | ||
48 | [PCI_DMA_BIDIRECTIONAL] = DATA_DIR_BYRECIPIENT, /* UNSPECIFIED */ | ||
49 | [PCI_DMA_TODEVICE] = DATA_DIR_OUT, /* OUTBOUND */ | ||
50 | [PCI_DMA_FROMDEVICE] = DATA_DIR_IN, /* INBOUND */ | ||
51 | [PCI_DMA_NONE] = DATA_DIR_NONE, /* NO TRANSFER */ | ||
52 | }; | ||
53 | |||
54 | static inline int asd_map_scatterlist(struct sas_task *task, | ||
55 | struct sg_el *sg_arr, | ||
56 | unsigned long gfp_flags) | ||
57 | { | ||
58 | struct asd_ascb *ascb = task->lldd_task; | ||
59 | struct asd_ha_struct *asd_ha = ascb->ha; | ||
60 | struct scatterlist *sc; | ||
61 | int num_sg, res; | ||
62 | |||
63 | if (task->data_dir == PCI_DMA_NONE) | ||
64 | return 0; | ||
65 | |||
66 | if (task->num_scatter == 0) { | ||
67 | void *p = task->scatter; | ||
68 | dma_addr_t dma = pci_map_single(asd_ha->pcidev, p, | ||
69 | task->total_xfer_len, | ||
70 | task->data_dir); | ||
71 | sg_arr[0].bus_addr = cpu_to_le64((u64)dma); | ||
72 | sg_arr[0].size = cpu_to_le32(task->total_xfer_len); | ||
73 | sg_arr[0].flags |= ASD_SG_EL_LIST_EOL; | ||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | num_sg = pci_map_sg(asd_ha->pcidev, task->scatter, task->num_scatter, | ||
78 | task->data_dir); | ||
79 | if (num_sg == 0) | ||
80 | return -ENOMEM; | ||
81 | |||
82 | if (num_sg > 3) { | ||
83 | int i; | ||
84 | |||
85 | ascb->sg_arr = asd_alloc_coherent(asd_ha, | ||
86 | num_sg*sizeof(struct sg_el), | ||
87 | gfp_flags); | ||
88 | if (!ascb->sg_arr) { | ||
89 | res = -ENOMEM; | ||
90 | goto err_unmap; | ||
91 | } | ||
92 | for (sc = task->scatter, i = 0; i < num_sg; i++, sc++) { | ||
93 | struct sg_el *sg = | ||
94 | &((struct sg_el *)ascb->sg_arr->vaddr)[i]; | ||
95 | sg->bus_addr = cpu_to_le64((u64)sg_dma_address(sc)); | ||
96 | sg->size = cpu_to_le32((u32)sg_dma_len(sc)); | ||
97 | if (i == num_sg-1) | ||
98 | sg->flags |= ASD_SG_EL_LIST_EOL; | ||
99 | } | ||
100 | |||
101 | for (sc = task->scatter, i = 0; i < 2; i++, sc++) { | ||
102 | sg_arr[i].bus_addr = | ||
103 | cpu_to_le64((u64)sg_dma_address(sc)); | ||
104 | sg_arr[i].size = cpu_to_le32((u32)sg_dma_len(sc)); | ||
105 | } | ||
106 | sg_arr[1].next_sg_offs = 2 * sizeof(*sg_arr); | ||
107 | sg_arr[1].flags |= ASD_SG_EL_LIST_EOS; | ||
108 | |||
109 | memset(&sg_arr[2], 0, sizeof(*sg_arr)); | ||
110 | sg_arr[2].bus_addr=cpu_to_le64((u64)ascb->sg_arr->dma_handle); | ||
111 | } else { | ||
112 | int i; | ||
113 | for (sc = task->scatter, i = 0; i < num_sg; i++, sc++) { | ||
114 | sg_arr[i].bus_addr = | ||
115 | cpu_to_le64((u64)sg_dma_address(sc)); | ||
116 | sg_arr[i].size = cpu_to_le32((u32)sg_dma_len(sc)); | ||
117 | } | ||
118 | sg_arr[i-1].flags |= ASD_SG_EL_LIST_EOL; | ||
119 | } | ||
120 | |||
121 | return 0; | ||
122 | err_unmap: | ||
123 | pci_unmap_sg(asd_ha->pcidev, task->scatter, task->num_scatter, | ||
124 | task->data_dir); | ||
125 | return res; | ||
126 | } | ||
127 | |||
128 | static inline void asd_unmap_scatterlist(struct asd_ascb *ascb) | ||
129 | { | ||
130 | struct asd_ha_struct *asd_ha = ascb->ha; | ||
131 | struct sas_task *task = ascb->uldd_task; | ||
132 | |||
133 | if (task->data_dir == PCI_DMA_NONE) | ||
134 | return; | ||
135 | |||
136 | if (task->num_scatter == 0) { | ||
137 | dma_addr_t dma = (dma_addr_t) | ||
138 | le64_to_cpu(ascb->scb->ssp_task.sg_element[0].bus_addr); | ||
139 | pci_unmap_single(ascb->ha->pcidev, dma, task->total_xfer_len, | ||
140 | task->data_dir); | ||
141 | return; | ||
142 | } | ||
143 | |||
144 | asd_free_coherent(asd_ha, ascb->sg_arr); | ||
145 | pci_unmap_sg(asd_ha->pcidev, task->scatter, task->num_scatter, | ||
146 | task->data_dir); | ||
147 | } | ||
148 | |||
149 | /* ---------- Task complete tasklet ---------- */ | ||
150 | |||
151 | static void asd_get_response_tasklet(struct asd_ascb *ascb, | ||
152 | struct done_list_struct *dl) | ||
153 | { | ||
154 | struct asd_ha_struct *asd_ha = ascb->ha; | ||
155 | struct sas_task *task = ascb->uldd_task; | ||
156 | struct task_status_struct *ts = &task->task_status; | ||
157 | unsigned long flags; | ||
158 | struct tc_resp_sb_struct { | ||
159 | __le16 index_escb; | ||
160 | u8 len_lsb; | ||
161 | u8 flags; | ||
162 | } __attribute__ ((packed)) *resp_sb = (void *) dl->status_block; | ||
163 | |||
164 | /* int size = ((resp_sb->flags & 7) << 8) | resp_sb->len_lsb; */ | ||
165 | int edb_id = ((resp_sb->flags & 0x70) >> 4)-1; | ||
166 | struct asd_ascb *escb; | ||
167 | struct asd_dma_tok *edb; | ||
168 | void *r; | ||
169 | |||
170 | spin_lock_irqsave(&asd_ha->seq.tc_index_lock, flags); | ||
171 | escb = asd_tc_index_find(&asd_ha->seq, | ||
172 | (int)le16_to_cpu(resp_sb->index_escb)); | ||
173 | spin_unlock_irqrestore(&asd_ha->seq.tc_index_lock, flags); | ||
174 | |||
175 | if (!escb) { | ||
176 | ASD_DPRINTK("Uh-oh! No escb for this dl?!\n"); | ||
177 | return; | ||
178 | } | ||
179 | |||
180 | ts->buf_valid_size = 0; | ||
181 | edb = asd_ha->seq.edb_arr[edb_id + escb->edb_index]; | ||
182 | r = edb->vaddr; | ||
183 | if (task->task_proto == SAS_PROTO_SSP) { | ||
184 | struct ssp_response_iu *iu = | ||
185 | r + 16 + sizeof(struct ssp_frame_hdr); | ||
186 | |||
187 | ts->residual = le32_to_cpu(*(__le32 *)r); | ||
188 | ts->resp = SAS_TASK_COMPLETE; | ||
189 | if (iu->datapres == 0) | ||
190 | ts->stat = iu->status; | ||
191 | else if (iu->datapres == 1) | ||
192 | ts->stat = iu->resp_data[3]; | ||
193 | else if (iu->datapres == 2) { | ||
194 | ts->stat = SAM_CHECK_COND; | ||
195 | ts->buf_valid_size = min((u32) SAS_STATUS_BUF_SIZE, | ||
196 | be32_to_cpu(iu->sense_data_len)); | ||
197 | memcpy(ts->buf, iu->sense_data, ts->buf_valid_size); | ||
198 | if (iu->status != SAM_CHECK_COND) { | ||
199 | ASD_DPRINTK("device %llx sent sense data, but " | ||
200 | "stat(0x%x) is not CHECK_CONDITION" | ||
201 | "\n", | ||
202 | SAS_ADDR(task->dev->sas_addr), | ||
203 | ts->stat); | ||
204 | } | ||
205 | } | ||
206 | } else { | ||
207 | struct ata_task_resp *resp = (void *) &ts->buf[0]; | ||
208 | |||
209 | ts->residual = le32_to_cpu(*(__le32 *)r); | ||
210 | |||
211 | if (SAS_STATUS_BUF_SIZE >= sizeof(*resp)) { | ||
212 | resp->frame_len = le16_to_cpu(*(__le16 *)(r+6)); | ||
213 | memcpy(&resp->ending_fis[0], r+16, 24); | ||
214 | ts->buf_valid_size = sizeof(*resp); | ||
215 | } | ||
216 | } | ||
217 | |||
218 | asd_invalidate_edb(escb, edb_id); | ||
219 | } | ||
220 | |||
221 | static void asd_task_tasklet_complete(struct asd_ascb *ascb, | ||
222 | struct done_list_struct *dl) | ||
223 | { | ||
224 | struct sas_task *task = ascb->uldd_task; | ||
225 | struct task_status_struct *ts = &task->task_status; | ||
226 | unsigned long flags; | ||
227 | u8 opcode = dl->opcode; | ||
228 | |||
229 | asd_can_dequeue(ascb->ha, 1); | ||
230 | |||
231 | Again: | ||
232 | switch (opcode) { | ||
233 | case TC_NO_ERROR: | ||
234 | ts->resp = SAS_TASK_COMPLETE; | ||
235 | ts->stat = SAM_GOOD; | ||
236 | break; | ||
237 | case TC_UNDERRUN: | ||
238 | ts->resp = SAS_TASK_COMPLETE; | ||
239 | ts->stat = SAS_DATA_UNDERRUN; | ||
240 | ts->residual = le32_to_cpu(*(__le32 *)dl->status_block); | ||
241 | break; | ||
242 | case TC_OVERRUN: | ||
243 | ts->resp = SAS_TASK_COMPLETE; | ||
244 | ts->stat = SAS_DATA_OVERRUN; | ||
245 | ts->residual = 0; | ||
246 | break; | ||
247 | case TC_SSP_RESP: | ||
248 | case TC_ATA_RESP: | ||
249 | ts->resp = SAS_TASK_COMPLETE; | ||
250 | ts->stat = SAS_PROTO_RESPONSE; | ||
251 | asd_get_response_tasklet(ascb, dl); | ||
252 | break; | ||
253 | case TF_OPEN_REJECT: | ||
254 | ts->resp = SAS_TASK_UNDELIVERED; | ||
255 | ts->stat = SAS_OPEN_REJECT; | ||
256 | if (dl->status_block[1] & 2) | ||
257 | ts->open_rej_reason = 1 + dl->status_block[2]; | ||
258 | else if (dl->status_block[1] & 1) | ||
259 | ts->open_rej_reason = (dl->status_block[2] >> 4)+10; | ||
260 | else | ||
261 | ts->open_rej_reason = SAS_OREJ_UNKNOWN; | ||
262 | break; | ||
263 | case TF_OPEN_TO: | ||
264 | ts->resp = SAS_TASK_UNDELIVERED; | ||
265 | ts->stat = SAS_OPEN_TO; | ||
266 | break; | ||
267 | case TF_PHY_DOWN: | ||
268 | case TU_PHY_DOWN: | ||
269 | ts->resp = SAS_TASK_UNDELIVERED; | ||
270 | ts->stat = SAS_PHY_DOWN; | ||
271 | break; | ||
272 | case TI_PHY_DOWN: | ||
273 | ts->resp = SAS_TASK_COMPLETE; | ||
274 | ts->stat = SAS_PHY_DOWN; | ||
275 | break; | ||
276 | case TI_BREAK: | ||
277 | case TI_PROTO_ERR: | ||
278 | case TI_NAK: | ||
279 | case TI_ACK_NAK_TO: | ||
280 | case TF_SMP_XMIT_RCV_ERR: | ||
281 | case TC_ATA_R_ERR_RECV: | ||
282 | ts->resp = SAS_TASK_COMPLETE; | ||
283 | ts->stat = SAS_INTERRUPTED; | ||
284 | break; | ||
285 | case TF_BREAK: | ||
286 | case TU_BREAK: | ||
287 | case TU_ACK_NAK_TO: | ||
288 | case TF_SMPRSP_TO: | ||
289 | ts->resp = SAS_TASK_UNDELIVERED; | ||
290 | ts->stat = SAS_DEV_NO_RESPONSE; | ||
291 | break; | ||
292 | case TF_NAK_RECV: | ||
293 | ts->resp = SAS_TASK_COMPLETE; | ||
294 | ts->stat = SAS_NAK_R_ERR; | ||
295 | break; | ||
296 | case TA_I_T_NEXUS_LOSS: | ||
297 | opcode = dl->status_block[0]; | ||
298 | goto Again; | ||
299 | break; | ||
300 | case TF_INV_CONN_HANDLE: | ||
301 | ts->resp = SAS_TASK_UNDELIVERED; | ||
302 | ts->stat = SAS_DEVICE_UNKNOWN; | ||
303 | break; | ||
304 | case TF_REQUESTED_N_PENDING: | ||
305 | ts->resp = SAS_TASK_UNDELIVERED; | ||
306 | ts->stat = SAS_PENDING; | ||
307 | break; | ||
308 | case TC_TASK_CLEARED: | ||
309 | case TA_ON_REQ: | ||
310 | ts->resp = SAS_TASK_COMPLETE; | ||
311 | ts->stat = SAS_ABORTED_TASK; | ||
312 | break; | ||
313 | |||
314 | case TF_NO_SMP_CONN: | ||
315 | case TF_TMF_NO_CTX: | ||
316 | case TF_TMF_NO_TAG: | ||
317 | case TF_TMF_TAG_FREE: | ||
318 | case TF_TMF_TASK_DONE: | ||
319 | case TF_TMF_NO_CONN_HANDLE: | ||
320 | case TF_IRTT_TO: | ||
321 | case TF_IU_SHORT: | ||
322 | case TF_DATA_OFFS_ERR: | ||
323 | ts->resp = SAS_TASK_UNDELIVERED; | ||
324 | ts->stat = SAS_DEV_NO_RESPONSE; | ||
325 | break; | ||
326 | |||
327 | case TC_LINK_ADM_RESP: | ||
328 | case TC_CONTROL_PHY: | ||
329 | case TC_RESUME: | ||
330 | case TC_PARTIAL_SG_LIST: | ||
331 | default: | ||
332 | ASD_DPRINTK("%s: dl opcode: 0x%x?\n", __FUNCTION__, opcode); | ||
333 | break; | ||
334 | } | ||
335 | |||
336 | switch (task->task_proto) { | ||
337 | case SATA_PROTO: | ||
338 | case SAS_PROTO_STP: | ||
339 | asd_unbuild_ata_ascb(ascb); | ||
340 | break; | ||
341 | case SAS_PROTO_SMP: | ||
342 | asd_unbuild_smp_ascb(ascb); | ||
343 | break; | ||
344 | case SAS_PROTO_SSP: | ||
345 | asd_unbuild_ssp_ascb(ascb); | ||
346 | default: | ||
347 | break; | ||
348 | } | ||
349 | |||
350 | spin_lock_irqsave(&task->task_state_lock, flags); | ||
351 | task->task_state_flags &= ~SAS_TASK_STATE_PENDING; | ||
352 | task->task_state_flags |= SAS_TASK_STATE_DONE; | ||
353 | if (unlikely((task->task_state_flags & SAS_TASK_STATE_ABORTED))) { | ||
354 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
355 | ASD_DPRINTK("task 0x%p done with opcode 0x%x resp 0x%x " | ||
356 | "stat 0x%x but aborted by upper layer!\n", | ||
357 | task, opcode, ts->resp, ts->stat); | ||
358 | complete(&ascb->completion); | ||
359 | } else { | ||
360 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
361 | task->lldd_task = NULL; | ||
362 | asd_ascb_free(ascb); | ||
363 | mb(); | ||
364 | task->task_done(task); | ||
365 | } | ||
366 | } | ||
367 | |||
368 | /* ---------- ATA ---------- */ | ||
369 | |||
370 | static int asd_build_ata_ascb(struct asd_ascb *ascb, struct sas_task *task, | ||
371 | unsigned long gfp_flags) | ||
372 | { | ||
373 | struct domain_device *dev = task->dev; | ||
374 | struct scb *scb; | ||
375 | u8 flags; | ||
376 | int res = 0; | ||
377 | |||
378 | scb = ascb->scb; | ||
379 | |||
380 | if (unlikely(task->ata_task.device_control_reg_update)) | ||
381 | scb->header.opcode = CONTROL_ATA_DEV; | ||
382 | else if (dev->sata_dev.command_set == ATA_COMMAND_SET) | ||
383 | scb->header.opcode = INITIATE_ATA_TASK; | ||
384 | else | ||
385 | scb->header.opcode = INITIATE_ATAPI_TASK; | ||
386 | |||
387 | scb->ata_task.proto_conn_rate = (1 << 5); /* STP */ | ||
388 | if (dev->port->oob_mode == SAS_OOB_MODE) | ||
389 | scb->ata_task.proto_conn_rate |= dev->linkrate; | ||
390 | |||
391 | scb->ata_task.total_xfer_len = cpu_to_le32(task->total_xfer_len); | ||
392 | scb->ata_task.fis = task->ata_task.fis; | ||
393 | scb->ata_task.fis.fis_type = 0x27; | ||
394 | if (likely(!task->ata_task.device_control_reg_update)) | ||
395 | scb->ata_task.fis.flags |= 0x80; /* C=1: update ATA cmd reg */ | ||
396 | scb->ata_task.fis.flags &= 0xF0; /* PM_PORT field shall be 0 */ | ||
397 | if (dev->sata_dev.command_set == ATAPI_COMMAND_SET) | ||
398 | memcpy(scb->ata_task.atapi_packet, task->ata_task.atapi_packet, | ||
399 | 16); | ||
400 | scb->ata_task.sister_scb = cpu_to_le16(0xFFFF); | ||
401 | scb->ata_task.conn_handle = cpu_to_le16( | ||
402 | (u16)(unsigned long)dev->lldd_dev); | ||
403 | |||
404 | if (likely(!task->ata_task.device_control_reg_update)) { | ||
405 | flags = 0; | ||
406 | if (task->ata_task.dma_xfer) | ||
407 | flags |= DATA_XFER_MODE_DMA; | ||
408 | if (task->ata_task.use_ncq && | ||
409 | dev->sata_dev.command_set != ATAPI_COMMAND_SET) | ||
410 | flags |= ATA_Q_TYPE_NCQ; | ||
411 | flags |= data_dir_flags[task->data_dir]; | ||
412 | scb->ata_task.ata_flags = flags; | ||
413 | |||
414 | scb->ata_task.retry_count = task->ata_task.retry_count; | ||
415 | |||
416 | flags = 0; | ||
417 | if (task->ata_task.set_affil_pol) | ||
418 | flags |= SET_AFFIL_POLICY; | ||
419 | if (task->ata_task.stp_affil_pol) | ||
420 | flags |= STP_AFFIL_POLICY; | ||
421 | scb->ata_task.flags = flags; | ||
422 | } | ||
423 | ascb->tasklet_complete = asd_task_tasklet_complete; | ||
424 | |||
425 | if (likely(!task->ata_task.device_control_reg_update)) | ||
426 | res = asd_map_scatterlist(task, scb->ata_task.sg_element, | ||
427 | gfp_flags); | ||
428 | |||
429 | return res; | ||
430 | } | ||
431 | |||
432 | static void asd_unbuild_ata_ascb(struct asd_ascb *a) | ||
433 | { | ||
434 | asd_unmap_scatterlist(a); | ||
435 | } | ||
436 | |||
437 | /* ---------- SMP ---------- */ | ||
438 | |||
439 | static int asd_build_smp_ascb(struct asd_ascb *ascb, struct sas_task *task, | ||
440 | unsigned long gfp_flags) | ||
441 | { | ||
442 | struct asd_ha_struct *asd_ha = ascb->ha; | ||
443 | struct domain_device *dev = task->dev; | ||
444 | struct scb *scb; | ||
445 | |||
446 | pci_map_sg(asd_ha->pcidev, &task->smp_task.smp_req, 1, | ||
447 | PCI_DMA_FROMDEVICE); | ||
448 | pci_map_sg(asd_ha->pcidev, &task->smp_task.smp_resp, 1, | ||
449 | PCI_DMA_FROMDEVICE); | ||
450 | |||
451 | scb = ascb->scb; | ||
452 | |||
453 | scb->header.opcode = INITIATE_SMP_TASK; | ||
454 | |||
455 | scb->smp_task.proto_conn_rate = dev->linkrate; | ||
456 | |||
457 | scb->smp_task.smp_req.bus_addr = | ||
458 | cpu_to_le64((u64)sg_dma_address(&task->smp_task.smp_req)); | ||
459 | scb->smp_task.smp_req.size = | ||
460 | cpu_to_le32((u32)sg_dma_len(&task->smp_task.smp_req)-4); | ||
461 | |||
462 | scb->smp_task.smp_resp.bus_addr = | ||
463 | cpu_to_le64((u64)sg_dma_address(&task->smp_task.smp_resp)); | ||
464 | scb->smp_task.smp_resp.size = | ||
465 | cpu_to_le32((u32)sg_dma_len(&task->smp_task.smp_resp)-4); | ||
466 | |||
467 | scb->smp_task.sister_scb = cpu_to_le16(0xFFFF); | ||
468 | scb->smp_task.conn_handle = cpu_to_le16((u16) | ||
469 | (unsigned long)dev->lldd_dev); | ||
470 | |||
471 | ascb->tasklet_complete = asd_task_tasklet_complete; | ||
472 | |||
473 | return 0; | ||
474 | } | ||
475 | |||
476 | static void asd_unbuild_smp_ascb(struct asd_ascb *a) | ||
477 | { | ||
478 | struct sas_task *task = a->uldd_task; | ||
479 | |||
480 | BUG_ON(!task); | ||
481 | pci_unmap_sg(a->ha->pcidev, &task->smp_task.smp_req, 1, | ||
482 | PCI_DMA_FROMDEVICE); | ||
483 | pci_unmap_sg(a->ha->pcidev, &task->smp_task.smp_resp, 1, | ||
484 | PCI_DMA_FROMDEVICE); | ||
485 | } | ||
486 | |||
487 | /* ---------- SSP ---------- */ | ||
488 | |||
489 | static int asd_build_ssp_ascb(struct asd_ascb *ascb, struct sas_task *task, | ||
490 | unsigned long gfp_flags) | ||
491 | { | ||
492 | struct domain_device *dev = task->dev; | ||
493 | struct scb *scb; | ||
494 | int res = 0; | ||
495 | |||
496 | scb = ascb->scb; | ||
497 | |||
498 | scb->header.opcode = INITIATE_SSP_TASK; | ||
499 | |||
500 | scb->ssp_task.proto_conn_rate = (1 << 4); /* SSP */ | ||
501 | scb->ssp_task.proto_conn_rate |= dev->linkrate; | ||
502 | scb->ssp_task.total_xfer_len = cpu_to_le32(task->total_xfer_len); | ||
503 | scb->ssp_task.ssp_frame.frame_type = SSP_DATA; | ||
504 | memcpy(scb->ssp_task.ssp_frame.hashed_dest_addr, dev->hashed_sas_addr, | ||
505 | HASHED_SAS_ADDR_SIZE); | ||
506 | memcpy(scb->ssp_task.ssp_frame.hashed_src_addr, | ||
507 | dev->port->ha->hashed_sas_addr, HASHED_SAS_ADDR_SIZE); | ||
508 | scb->ssp_task.ssp_frame.tptt = cpu_to_be16(0xFFFF); | ||
509 | |||
510 | memcpy(scb->ssp_task.ssp_cmd.lun, task->ssp_task.LUN, 8); | ||
511 | if (task->ssp_task.enable_first_burst) | ||
512 | scb->ssp_task.ssp_cmd.efb_prio_attr |= EFB_MASK; | ||
513 | scb->ssp_task.ssp_cmd.efb_prio_attr |= (task->ssp_task.task_prio << 3); | ||
514 | scb->ssp_task.ssp_cmd.efb_prio_attr |= (task->ssp_task.task_attr & 7); | ||
515 | memcpy(scb->ssp_task.ssp_cmd.cdb, task->ssp_task.cdb, 16); | ||
516 | |||
517 | scb->ssp_task.sister_scb = cpu_to_le16(0xFFFF); | ||
518 | scb->ssp_task.conn_handle = cpu_to_le16( | ||
519 | (u16)(unsigned long)dev->lldd_dev); | ||
520 | scb->ssp_task.data_dir = data_dir_flags[task->data_dir]; | ||
521 | scb->ssp_task.retry_count = scb->ssp_task.retry_count; | ||
522 | |||
523 | ascb->tasklet_complete = asd_task_tasklet_complete; | ||
524 | |||
525 | res = asd_map_scatterlist(task, scb->ssp_task.sg_element, gfp_flags); | ||
526 | |||
527 | return res; | ||
528 | } | ||
529 | |||
530 | static void asd_unbuild_ssp_ascb(struct asd_ascb *a) | ||
531 | { | ||
532 | asd_unmap_scatterlist(a); | ||
533 | } | ||
534 | |||
535 | /* ---------- Execute Task ---------- */ | ||
536 | |||
537 | static inline int asd_can_queue(struct asd_ha_struct *asd_ha, int num) | ||
538 | { | ||
539 | int res = 0; | ||
540 | unsigned long flags; | ||
541 | |||
542 | spin_lock_irqsave(&asd_ha->seq.pend_q_lock, flags); | ||
543 | if ((asd_ha->seq.can_queue - num) < 0) | ||
544 | res = -SAS_QUEUE_FULL; | ||
545 | else | ||
546 | asd_ha->seq.can_queue -= num; | ||
547 | spin_unlock_irqrestore(&asd_ha->seq.pend_q_lock, flags); | ||
548 | |||
549 | return res; | ||
550 | } | ||
551 | |||
552 | int asd_execute_task(struct sas_task *task, const int num, | ||
553 | unsigned long gfp_flags) | ||
554 | { | ||
555 | int res = 0; | ||
556 | LIST_HEAD(alist); | ||
557 | struct sas_task *t = task; | ||
558 | struct asd_ascb *ascb = NULL, *a; | ||
559 | struct asd_ha_struct *asd_ha = task->dev->port->ha->lldd_ha; | ||
560 | |||
561 | res = asd_can_queue(asd_ha, num); | ||
562 | if (res) | ||
563 | return res; | ||
564 | |||
565 | res = num; | ||
566 | ascb = asd_ascb_alloc_list(asd_ha, &res, gfp_flags); | ||
567 | if (res) { | ||
568 | res = -ENOMEM; | ||
569 | goto out_err; | ||
570 | } | ||
571 | |||
572 | __list_add(&alist, ascb->list.prev, &ascb->list); | ||
573 | list_for_each_entry(a, &alist, list) { | ||
574 | a->uldd_task = t; | ||
575 | t->lldd_task = a; | ||
576 | t = list_entry(t->list.next, struct sas_task, list); | ||
577 | } | ||
578 | list_for_each_entry(a, &alist, list) { | ||
579 | t = a->uldd_task; | ||
580 | a->uldd_timer = 1; | ||
581 | if (t->task_proto & SAS_PROTO_STP) | ||
582 | t->task_proto = SAS_PROTO_STP; | ||
583 | switch (t->task_proto) { | ||
584 | case SATA_PROTO: | ||
585 | case SAS_PROTO_STP: | ||
586 | res = asd_build_ata_ascb(a, t, gfp_flags); | ||
587 | break; | ||
588 | case SAS_PROTO_SMP: | ||
589 | res = asd_build_smp_ascb(a, t, gfp_flags); | ||
590 | break; | ||
591 | case SAS_PROTO_SSP: | ||
592 | res = asd_build_ssp_ascb(a, t, gfp_flags); | ||
593 | break; | ||
594 | default: | ||
595 | asd_printk("unknown sas_task proto: 0x%x\n", | ||
596 | t->task_proto); | ||
597 | res = -ENOMEM; | ||
598 | break; | ||
599 | } | ||
600 | if (res) | ||
601 | goto out_err_unmap; | ||
602 | } | ||
603 | list_del_init(&alist); | ||
604 | |||
605 | res = asd_post_ascb_list(asd_ha, ascb, num); | ||
606 | if (unlikely(res)) { | ||
607 | a = NULL; | ||
608 | __list_add(&alist, ascb->list.prev, &ascb->list); | ||
609 | goto out_err_unmap; | ||
610 | } | ||
611 | |||
612 | return 0; | ||
613 | out_err_unmap: | ||
614 | { | ||
615 | struct asd_ascb *b = a; | ||
616 | list_for_each_entry(a, &alist, list) { | ||
617 | if (a == b) | ||
618 | break; | ||
619 | t = a->uldd_task; | ||
620 | switch (t->task_proto) { | ||
621 | case SATA_PROTO: | ||
622 | case SAS_PROTO_STP: | ||
623 | asd_unbuild_ata_ascb(a); | ||
624 | break; | ||
625 | case SAS_PROTO_SMP: | ||
626 | asd_unbuild_smp_ascb(a); | ||
627 | break; | ||
628 | case SAS_PROTO_SSP: | ||
629 | asd_unbuild_ssp_ascb(a); | ||
630 | default: | ||
631 | break; | ||
632 | } | ||
633 | t->lldd_task = NULL; | ||
634 | } | ||
635 | } | ||
636 | list_del_init(&alist); | ||
637 | out_err: | ||
638 | if (ascb) | ||
639 | asd_ascb_free_list(ascb); | ||
640 | asd_can_dequeue(asd_ha, num); | ||
641 | return res; | ||
642 | } | ||
diff --git a/drivers/scsi/aic94xx/aic94xx_tmf.c b/drivers/scsi/aic94xx/aic94xx_tmf.c new file mode 100644 index 000000000000..61234384503b --- /dev/null +++ b/drivers/scsi/aic94xx/aic94xx_tmf.c | |||
@@ -0,0 +1,636 @@ | |||
1 | /* | ||
2 | * Aic94xx Task Management Functions | ||
3 | * | ||
4 | * Copyright (C) 2005 Adaptec, Inc. All rights reserved. | ||
5 | * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> | ||
6 | * | ||
7 | * This file is licensed under GPLv2. | ||
8 | * | ||
9 | * This file is part of the aic94xx driver. | ||
10 | * | ||
11 | * The aic94xx driver is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License as | ||
13 | * published by the Free Software Foundation; version 2 of the | ||
14 | * License. | ||
15 | * | ||
16 | * The aic94xx driver is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
19 | * General Public License for more details. | ||
20 | * | ||
21 | * You should have received a copy of the GNU General Public License | ||
22 | * along with the aic94xx driver; if not, write to the Free Software | ||
23 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
24 | * | ||
25 | */ | ||
26 | |||
27 | #include <linux/spinlock.h> | ||
28 | #include "aic94xx.h" | ||
29 | #include "aic94xx_sas.h" | ||
30 | #include "aic94xx_hwi.h" | ||
31 | |||
32 | /* ---------- Internal enqueue ---------- */ | ||
33 | |||
34 | static int asd_enqueue_internal(struct asd_ascb *ascb, | ||
35 | void (*tasklet_complete)(struct asd_ascb *, | ||
36 | struct done_list_struct *), | ||
37 | void (*timed_out)(unsigned long)) | ||
38 | { | ||
39 | int res; | ||
40 | |||
41 | ascb->tasklet_complete = tasklet_complete; | ||
42 | ascb->uldd_timer = 1; | ||
43 | |||
44 | ascb->timer.data = (unsigned long) ascb; | ||
45 | ascb->timer.function = timed_out; | ||
46 | ascb->timer.expires = jiffies + AIC94XX_SCB_TIMEOUT; | ||
47 | |||
48 | add_timer(&ascb->timer); | ||
49 | |||
50 | res = asd_post_ascb_list(ascb->ha, ascb, 1); | ||
51 | if (unlikely(res)) | ||
52 | del_timer(&ascb->timer); | ||
53 | return res; | ||
54 | } | ||
55 | |||
56 | static inline void asd_timedout_common(unsigned long data) | ||
57 | { | ||
58 | struct asd_ascb *ascb = (void *) data; | ||
59 | struct asd_seq_data *seq = &ascb->ha->seq; | ||
60 | unsigned long flags; | ||
61 | |||
62 | spin_lock_irqsave(&seq->pend_q_lock, flags); | ||
63 | seq->pending--; | ||
64 | list_del_init(&ascb->list); | ||
65 | spin_unlock_irqrestore(&seq->pend_q_lock, flags); | ||
66 | } | ||
67 | |||
68 | /* ---------- CLEAR NEXUS ---------- */ | ||
69 | |||
70 | static void asd_clear_nexus_tasklet_complete(struct asd_ascb *ascb, | ||
71 | struct done_list_struct *dl) | ||
72 | { | ||
73 | ASD_DPRINTK("%s: here\n", __FUNCTION__); | ||
74 | if (!del_timer(&ascb->timer)) { | ||
75 | ASD_DPRINTK("%s: couldn't delete timer\n", __FUNCTION__); | ||
76 | return; | ||
77 | } | ||
78 | ASD_DPRINTK("%s: opcode: 0x%x\n", __FUNCTION__, dl->opcode); | ||
79 | ascb->uldd_task = (void *) (unsigned long) dl->opcode; | ||
80 | complete(&ascb->completion); | ||
81 | } | ||
82 | |||
83 | static void asd_clear_nexus_timedout(unsigned long data) | ||
84 | { | ||
85 | struct asd_ascb *ascb = (void *) data; | ||
86 | |||
87 | ASD_DPRINTK("%s: here\n", __FUNCTION__); | ||
88 | asd_timedout_common(data); | ||
89 | ascb->uldd_task = (void *) TMF_RESP_FUNC_FAILED; | ||
90 | complete(&ascb->completion); | ||
91 | } | ||
92 | |||
93 | #define CLEAR_NEXUS_PRE \ | ||
94 | ASD_DPRINTK("%s: PRE\n", __FUNCTION__); \ | ||
95 | res = 1; \ | ||
96 | ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL); \ | ||
97 | if (!ascb) \ | ||
98 | return -ENOMEM; \ | ||
99 | \ | ||
100 | scb = ascb->scb; \ | ||
101 | scb->header.opcode = CLEAR_NEXUS | ||
102 | |||
103 | #define CLEAR_NEXUS_POST \ | ||
104 | ASD_DPRINTK("%s: POST\n", __FUNCTION__); \ | ||
105 | res = asd_enqueue_internal(ascb, asd_clear_nexus_tasklet_complete, \ | ||
106 | asd_clear_nexus_timedout); \ | ||
107 | if (res) \ | ||
108 | goto out_err; \ | ||
109 | ASD_DPRINTK("%s: clear nexus posted, waiting...\n", __FUNCTION__); \ | ||
110 | wait_for_completion(&ascb->completion); \ | ||
111 | res = (int) (unsigned long) ascb->uldd_task; \ | ||
112 | if (res == TC_NO_ERROR) \ | ||
113 | res = TMF_RESP_FUNC_COMPLETE; \ | ||
114 | out_err: \ | ||
115 | asd_ascb_free(ascb); \ | ||
116 | return res | ||
117 | |||
118 | int asd_clear_nexus_ha(struct sas_ha_struct *sas_ha) | ||
119 | { | ||
120 | struct asd_ha_struct *asd_ha = sas_ha->lldd_ha; | ||
121 | struct asd_ascb *ascb; | ||
122 | struct scb *scb; | ||
123 | int res; | ||
124 | |||
125 | CLEAR_NEXUS_PRE; | ||
126 | scb->clear_nexus.nexus = NEXUS_ADAPTER; | ||
127 | CLEAR_NEXUS_POST; | ||
128 | } | ||
129 | |||
130 | int asd_clear_nexus_port(struct asd_sas_port *port) | ||
131 | { | ||
132 | struct asd_ha_struct *asd_ha = port->ha->lldd_ha; | ||
133 | struct asd_ascb *ascb; | ||
134 | struct scb *scb; | ||
135 | int res; | ||
136 | |||
137 | CLEAR_NEXUS_PRE; | ||
138 | scb->clear_nexus.nexus = NEXUS_PORT; | ||
139 | scb->clear_nexus.conn_mask = port->phy_mask; | ||
140 | CLEAR_NEXUS_POST; | ||
141 | } | ||
142 | |||
143 | #if 0 | ||
144 | static int asd_clear_nexus_I_T(struct domain_device *dev) | ||
145 | { | ||
146 | struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha; | ||
147 | struct asd_ascb *ascb; | ||
148 | struct scb *scb; | ||
149 | int res; | ||
150 | |||
151 | CLEAR_NEXUS_PRE; | ||
152 | scb->clear_nexus.nexus = NEXUS_I_T; | ||
153 | scb->clear_nexus.flags = SEND_Q | EXEC_Q | NOTINQ; | ||
154 | if (dev->tproto) | ||
155 | scb->clear_nexus.flags |= SUSPEND_TX; | ||
156 | scb->clear_nexus.conn_handle = cpu_to_le16((u16)(unsigned long) | ||
157 | dev->lldd_dev); | ||
158 | CLEAR_NEXUS_POST; | ||
159 | } | ||
160 | #endif | ||
161 | |||
162 | static int asd_clear_nexus_I_T_L(struct domain_device *dev, u8 *lun) | ||
163 | { | ||
164 | struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha; | ||
165 | struct asd_ascb *ascb; | ||
166 | struct scb *scb; | ||
167 | int res; | ||
168 | |||
169 | CLEAR_NEXUS_PRE; | ||
170 | scb->clear_nexus.nexus = NEXUS_I_T_L; | ||
171 | scb->clear_nexus.flags = SEND_Q | EXEC_Q | NOTINQ; | ||
172 | if (dev->tproto) | ||
173 | scb->clear_nexus.flags |= SUSPEND_TX; | ||
174 | memcpy(scb->clear_nexus.ssp_task.lun, lun, 8); | ||
175 | scb->clear_nexus.conn_handle = cpu_to_le16((u16)(unsigned long) | ||
176 | dev->lldd_dev); | ||
177 | CLEAR_NEXUS_POST; | ||
178 | } | ||
179 | |||
180 | static int asd_clear_nexus_tag(struct sas_task *task) | ||
181 | { | ||
182 | struct asd_ha_struct *asd_ha = task->dev->port->ha->lldd_ha; | ||
183 | struct asd_ascb *tascb = task->lldd_task; | ||
184 | struct asd_ascb *ascb; | ||
185 | struct scb *scb; | ||
186 | int res; | ||
187 | |||
188 | CLEAR_NEXUS_PRE; | ||
189 | scb->clear_nexus.nexus = NEXUS_TAG; | ||
190 | memcpy(scb->clear_nexus.ssp_task.lun, task->ssp_task.LUN, 8); | ||
191 | scb->clear_nexus.ssp_task.tag = tascb->tag; | ||
192 | if (task->dev->tproto) | ||
193 | scb->clear_nexus.conn_handle = cpu_to_le16((u16)(unsigned long) | ||
194 | task->dev->lldd_dev); | ||
195 | CLEAR_NEXUS_POST; | ||
196 | } | ||
197 | |||
198 | static int asd_clear_nexus_index(struct sas_task *task) | ||
199 | { | ||
200 | struct asd_ha_struct *asd_ha = task->dev->port->ha->lldd_ha; | ||
201 | struct asd_ascb *tascb = task->lldd_task; | ||
202 | struct asd_ascb *ascb; | ||
203 | struct scb *scb; | ||
204 | int res; | ||
205 | |||
206 | CLEAR_NEXUS_PRE; | ||
207 | scb->clear_nexus.nexus = NEXUS_TRANS_CX; | ||
208 | if (task->dev->tproto) | ||
209 | scb->clear_nexus.conn_handle = cpu_to_le16((u16)(unsigned long) | ||
210 | task->dev->lldd_dev); | ||
211 | scb->clear_nexus.index = cpu_to_le16(tascb->tc_index); | ||
212 | CLEAR_NEXUS_POST; | ||
213 | } | ||
214 | |||
215 | /* ---------- TMFs ---------- */ | ||
216 | |||
217 | static void asd_tmf_timedout(unsigned long data) | ||
218 | { | ||
219 | struct asd_ascb *ascb = (void *) data; | ||
220 | |||
221 | ASD_DPRINTK("tmf timed out\n"); | ||
222 | asd_timedout_common(data); | ||
223 | ascb->uldd_task = (void *) TMF_RESP_FUNC_FAILED; | ||
224 | complete(&ascb->completion); | ||
225 | } | ||
226 | |||
227 | static int asd_get_tmf_resp_tasklet(struct asd_ascb *ascb, | ||
228 | struct done_list_struct *dl) | ||
229 | { | ||
230 | struct asd_ha_struct *asd_ha = ascb->ha; | ||
231 | unsigned long flags; | ||
232 | struct tc_resp_sb_struct { | ||
233 | __le16 index_escb; | ||
234 | u8 len_lsb; | ||
235 | u8 flags; | ||
236 | } __attribute__ ((packed)) *resp_sb = (void *) dl->status_block; | ||
237 | |||
238 | int edb_id = ((resp_sb->flags & 0x70) >> 4)-1; | ||
239 | struct asd_ascb *escb; | ||
240 | struct asd_dma_tok *edb; | ||
241 | struct ssp_frame_hdr *fh; | ||
242 | struct ssp_response_iu *ru; | ||
243 | int res = TMF_RESP_FUNC_FAILED; | ||
244 | |||
245 | ASD_DPRINTK("tmf resp tasklet\n"); | ||
246 | |||
247 | spin_lock_irqsave(&asd_ha->seq.tc_index_lock, flags); | ||
248 | escb = asd_tc_index_find(&asd_ha->seq, | ||
249 | (int)le16_to_cpu(resp_sb->index_escb)); | ||
250 | spin_unlock_irqrestore(&asd_ha->seq.tc_index_lock, flags); | ||
251 | |||
252 | if (!escb) { | ||
253 | ASD_DPRINTK("Uh-oh! No escb for this dl?!\n"); | ||
254 | return res; | ||
255 | } | ||
256 | |||
257 | edb = asd_ha->seq.edb_arr[edb_id + escb->edb_index]; | ||
258 | ascb->tag = *(__be16 *)(edb->vaddr+4); | ||
259 | fh = edb->vaddr + 16; | ||
260 | ru = edb->vaddr + 16 + sizeof(*fh); | ||
261 | res = ru->status; | ||
262 | if (ru->datapres == 1) /* Response data present */ | ||
263 | res = ru->resp_data[3]; | ||
264 | #if 0 | ||
265 | ascb->tag = fh->tag; | ||
266 | #endif | ||
267 | ascb->tag_valid = 1; | ||
268 | |||
269 | asd_invalidate_edb(escb, edb_id); | ||
270 | return res; | ||
271 | } | ||
272 | |||
273 | static void asd_tmf_tasklet_complete(struct asd_ascb *ascb, | ||
274 | struct done_list_struct *dl) | ||
275 | { | ||
276 | if (!del_timer(&ascb->timer)) | ||
277 | return; | ||
278 | |||
279 | ASD_DPRINTK("tmf tasklet complete\n"); | ||
280 | |||
281 | if (dl->opcode == TC_SSP_RESP) | ||
282 | ascb->uldd_task = (void *) (unsigned long) | ||
283 | asd_get_tmf_resp_tasklet(ascb, dl); | ||
284 | else | ||
285 | ascb->uldd_task = (void *) 0xFF00 + (unsigned long) dl->opcode; | ||
286 | |||
287 | complete(&ascb->completion); | ||
288 | } | ||
289 | |||
290 | static inline int asd_clear_nexus(struct sas_task *task) | ||
291 | { | ||
292 | int res = TMF_RESP_FUNC_FAILED; | ||
293 | struct asd_ascb *tascb = task->lldd_task; | ||
294 | unsigned long flags; | ||
295 | |||
296 | ASD_DPRINTK("task not done, clearing nexus\n"); | ||
297 | if (tascb->tag_valid) | ||
298 | res = asd_clear_nexus_tag(task); | ||
299 | else | ||
300 | res = asd_clear_nexus_index(task); | ||
301 | wait_for_completion_timeout(&tascb->completion, | ||
302 | AIC94XX_SCB_TIMEOUT); | ||
303 | ASD_DPRINTK("came back from clear nexus\n"); | ||
304 | spin_lock_irqsave(&task->task_state_lock, flags); | ||
305 | if (task->task_state_flags & SAS_TASK_STATE_DONE) | ||
306 | res = TMF_RESP_FUNC_COMPLETE; | ||
307 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
308 | |||
309 | return res; | ||
310 | } | ||
311 | |||
312 | /** | ||
313 | * asd_abort_task -- ABORT TASK TMF | ||
314 | * @task: the task to be aborted | ||
315 | * | ||
316 | * Before calling ABORT TASK the task state flags should be ORed with | ||
317 | * SAS_TASK_STATE_ABORTED (unless SAS_TASK_STATE_DONE is set) under | ||
318 | * the task_state_lock IRQ spinlock, then ABORT TASK *must* be called. | ||
319 | * | ||
320 | * Implements the ABORT TASK TMF, I_T_L_Q nexus. | ||
321 | * Returns: SAS TMF responses (see sas_task.h), | ||
322 | * -ENOMEM, | ||
323 | * -SAS_QUEUE_FULL. | ||
324 | * | ||
325 | * When ABORT TASK returns, the caller of ABORT TASK checks first the | ||
326 | * task->task_state_flags, and then the return value of ABORT TASK. | ||
327 | * | ||
328 | * If the task has task state bit SAS_TASK_STATE_DONE set, then the | ||
329 | * task was completed successfully prior to it being aborted. The | ||
330 | * caller of ABORT TASK has responsibility to call task->task_done() | ||
331 | * xor free the task, depending on their framework. The return code | ||
332 | * is TMF_RESP_FUNC_FAILED in this case. | ||
333 | * | ||
334 | * Else the SAS_TASK_STATE_DONE bit is not set, | ||
335 | * If the return code is TMF_RESP_FUNC_COMPLETE, then | ||
336 | * the task was aborted successfully. The caller of | ||
337 | * ABORT TASK has responsibility to call task->task_done() | ||
338 | * to finish the task, xor free the task depending on their | ||
339 | * framework. | ||
340 | * else | ||
341 | * the ABORT TASK returned some kind of error. The task | ||
342 | * was _not_ cancelled. Nothing can be assumed. | ||
343 | * The caller of ABORT TASK may wish to retry. | ||
344 | */ | ||
345 | int asd_abort_task(struct sas_task *task) | ||
346 | { | ||
347 | struct asd_ascb *tascb = task->lldd_task; | ||
348 | struct asd_ha_struct *asd_ha = tascb->ha; | ||
349 | int res = 1; | ||
350 | unsigned long flags; | ||
351 | struct asd_ascb *ascb = NULL; | ||
352 | struct scb *scb; | ||
353 | |||
354 | spin_lock_irqsave(&task->task_state_lock, flags); | ||
355 | if (task->task_state_flags & SAS_TASK_STATE_DONE) { | ||
356 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
357 | res = TMF_RESP_FUNC_COMPLETE; | ||
358 | ASD_DPRINTK("%s: task 0x%p done\n", __FUNCTION__, task); | ||
359 | goto out_done; | ||
360 | } | ||
361 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
362 | |||
363 | ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL); | ||
364 | if (!ascb) | ||
365 | return -ENOMEM; | ||
366 | scb = ascb->scb; | ||
367 | |||
368 | scb->header.opcode = ABORT_TASK; | ||
369 | |||
370 | switch (task->task_proto) { | ||
371 | case SATA_PROTO: | ||
372 | case SAS_PROTO_STP: | ||
373 | scb->abort_task.proto_conn_rate = (1 << 5); /* STP */ | ||
374 | break; | ||
375 | case SAS_PROTO_SSP: | ||
376 | scb->abort_task.proto_conn_rate = (1 << 4); /* SSP */ | ||
377 | scb->abort_task.proto_conn_rate |= task->dev->linkrate; | ||
378 | break; | ||
379 | case SAS_PROTO_SMP: | ||
380 | break; | ||
381 | default: | ||
382 | break; | ||
383 | } | ||
384 | |||
385 | if (task->task_proto == SAS_PROTO_SSP) { | ||
386 | scb->abort_task.ssp_frame.frame_type = SSP_TASK; | ||
387 | memcpy(scb->abort_task.ssp_frame.hashed_dest_addr, | ||
388 | task->dev->hashed_sas_addr, HASHED_SAS_ADDR_SIZE); | ||
389 | memcpy(scb->abort_task.ssp_frame.hashed_src_addr, | ||
390 | task->dev->port->ha->hashed_sas_addr, | ||
391 | HASHED_SAS_ADDR_SIZE); | ||
392 | scb->abort_task.ssp_frame.tptt = cpu_to_be16(0xFFFF); | ||
393 | |||
394 | memcpy(scb->abort_task.ssp_task.lun, task->ssp_task.LUN, 8); | ||
395 | scb->abort_task.ssp_task.tmf = TMF_ABORT_TASK; | ||
396 | scb->abort_task.ssp_task.tag = cpu_to_be16(0xFFFF); | ||
397 | } | ||
398 | |||
399 | scb->abort_task.sister_scb = cpu_to_le16(0xFFFF); | ||
400 | scb->abort_task.conn_handle = cpu_to_le16( | ||
401 | (u16)(unsigned long)task->dev->lldd_dev); | ||
402 | scb->abort_task.retry_count = 1; | ||
403 | scb->abort_task.index = cpu_to_le16((u16)tascb->tc_index); | ||
404 | scb->abort_task.itnl_to = cpu_to_le16(ITNL_TIMEOUT_CONST); | ||
405 | |||
406 | res = asd_enqueue_internal(ascb, asd_tmf_tasklet_complete, | ||
407 | asd_tmf_timedout); | ||
408 | if (res) | ||
409 | goto out; | ||
410 | wait_for_completion(&ascb->completion); | ||
411 | ASD_DPRINTK("tmf came back\n"); | ||
412 | |||
413 | res = (int) (unsigned long) ascb->uldd_task; | ||
414 | tascb->tag = ascb->tag; | ||
415 | tascb->tag_valid = ascb->tag_valid; | ||
416 | |||
417 | spin_lock_irqsave(&task->task_state_lock, flags); | ||
418 | if (task->task_state_flags & SAS_TASK_STATE_DONE) { | ||
419 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
420 | res = TMF_RESP_FUNC_COMPLETE; | ||
421 | ASD_DPRINTK("%s: task 0x%p done\n", __FUNCTION__, task); | ||
422 | goto out_done; | ||
423 | } | ||
424 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
425 | |||
426 | switch (res) { | ||
427 | /* The task to be aborted has been sent to the device. | ||
428 | * We got a Response IU for the ABORT TASK TMF. */ | ||
429 | case TC_NO_ERROR + 0xFF00: | ||
430 | case TMF_RESP_FUNC_COMPLETE: | ||
431 | case TMF_RESP_FUNC_FAILED: | ||
432 | res = asd_clear_nexus(task); | ||
433 | break; | ||
434 | case TMF_RESP_INVALID_FRAME: | ||
435 | case TMF_RESP_OVERLAPPED_TAG: | ||
436 | case TMF_RESP_FUNC_ESUPP: | ||
437 | case TMF_RESP_NO_LUN: | ||
438 | goto out_done; break; | ||
439 | } | ||
440 | /* In the following we assume that the managing layer | ||
441 | * will _never_ make a mistake, when issuing ABORT TASK. | ||
442 | */ | ||
443 | switch (res) { | ||
444 | default: | ||
445 | res = asd_clear_nexus(task); | ||
446 | /* fallthrough */ | ||
447 | case TC_NO_ERROR + 0xFF00: | ||
448 | case TMF_RESP_FUNC_COMPLETE: | ||
449 | break; | ||
450 | /* The task hasn't been sent to the device xor we never got | ||
451 | * a (sane) Response IU for the ABORT TASK TMF. | ||
452 | */ | ||
453 | case TF_NAK_RECV + 0xFF00: | ||
454 | res = TMF_RESP_INVALID_FRAME; | ||
455 | break; | ||
456 | case TF_TMF_TASK_DONE + 0xFF00: /* done but not reported yet */ | ||
457 | res = TMF_RESP_FUNC_FAILED; | ||
458 | wait_for_completion_timeout(&tascb->completion, | ||
459 | AIC94XX_SCB_TIMEOUT); | ||
460 | spin_lock_irqsave(&task->task_state_lock, flags); | ||
461 | if (task->task_state_flags & SAS_TASK_STATE_DONE) | ||
462 | res = TMF_RESP_FUNC_COMPLETE; | ||
463 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
464 | goto out_done; | ||
465 | case TF_TMF_NO_TAG + 0xFF00: | ||
466 | case TF_TMF_TAG_FREE + 0xFF00: /* the tag is in the free list */ | ||
467 | case TF_TMF_NO_CONN_HANDLE + 0xFF00: /* no such device */ | ||
468 | res = TMF_RESP_FUNC_COMPLETE; | ||
469 | goto out_done; | ||
470 | case TF_TMF_NO_CTX + 0xFF00: /* not in seq, or proto != SSP */ | ||
471 | res = TMF_RESP_FUNC_ESUPP; | ||
472 | goto out; | ||
473 | } | ||
474 | out_done: | ||
475 | if (res == TMF_RESP_FUNC_COMPLETE) { | ||
476 | task->lldd_task = NULL; | ||
477 | mb(); | ||
478 | asd_ascb_free(tascb); | ||
479 | } | ||
480 | out: | ||
481 | asd_ascb_free(ascb); | ||
482 | ASD_DPRINTK("task 0x%p aborted, res: 0x%x\n", task, res); | ||
483 | return res; | ||
484 | } | ||
485 | |||
486 | /** | ||
487 | * asd_initiate_ssp_tmf -- send a TMF to an I_T_L or I_T_L_Q nexus | ||
488 | * @dev: pointer to struct domain_device of interest | ||
489 | * @lun: pointer to u8[8] which is the LUN | ||
490 | * @tmf: the TMF to be performed (see sas_task.h or the SAS spec) | ||
491 | * @index: the transaction context of the task to be queried if QT TMF | ||
492 | * | ||
493 | * This function is used to send ABORT TASK SET, CLEAR ACA, | ||
494 | * CLEAR TASK SET, LU RESET and QUERY TASK TMFs. | ||
495 | * | ||
496 | * No SCBs should be queued to the I_T_L nexus when this SCB is | ||
497 | * pending. | ||
498 | * | ||
499 | * Returns: TMF response code (see sas_task.h or the SAS spec) | ||
500 | */ | ||
501 | static int asd_initiate_ssp_tmf(struct domain_device *dev, u8 *lun, | ||
502 | int tmf, int index) | ||
503 | { | ||
504 | struct asd_ha_struct *asd_ha = dev->port->ha->lldd_ha; | ||
505 | struct asd_ascb *ascb; | ||
506 | int res = 1; | ||
507 | struct scb *scb; | ||
508 | |||
509 | if (!(dev->tproto & SAS_PROTO_SSP)) | ||
510 | return TMF_RESP_FUNC_ESUPP; | ||
511 | |||
512 | ascb = asd_ascb_alloc_list(asd_ha, &res, GFP_KERNEL); | ||
513 | if (!ascb) | ||
514 | return -ENOMEM; | ||
515 | scb = ascb->scb; | ||
516 | |||
517 | if (tmf == TMF_QUERY_TASK) | ||
518 | scb->header.opcode = QUERY_SSP_TASK; | ||
519 | else | ||
520 | scb->header.opcode = INITIATE_SSP_TMF; | ||
521 | |||
522 | scb->ssp_tmf.proto_conn_rate = (1 << 4); /* SSP */ | ||
523 | scb->ssp_tmf.proto_conn_rate |= dev->linkrate; | ||
524 | /* SSP frame header */ | ||
525 | scb->ssp_tmf.ssp_frame.frame_type = SSP_TASK; | ||
526 | memcpy(scb->ssp_tmf.ssp_frame.hashed_dest_addr, | ||
527 | dev->hashed_sas_addr, HASHED_SAS_ADDR_SIZE); | ||
528 | memcpy(scb->ssp_tmf.ssp_frame.hashed_src_addr, | ||
529 | dev->port->ha->hashed_sas_addr, HASHED_SAS_ADDR_SIZE); | ||
530 | scb->ssp_tmf.ssp_frame.tptt = cpu_to_be16(0xFFFF); | ||
531 | /* SSP Task IU */ | ||
532 | memcpy(scb->ssp_tmf.ssp_task.lun, lun, 8); | ||
533 | scb->ssp_tmf.ssp_task.tmf = tmf; | ||
534 | |||
535 | scb->ssp_tmf.sister_scb = cpu_to_le16(0xFFFF); | ||
536 | scb->ssp_tmf.conn_handle= cpu_to_le16((u16)(unsigned long) | ||
537 | dev->lldd_dev); | ||
538 | scb->ssp_tmf.retry_count = 1; | ||
539 | scb->ssp_tmf.itnl_to = cpu_to_le16(ITNL_TIMEOUT_CONST); | ||
540 | if (tmf == TMF_QUERY_TASK) | ||
541 | scb->ssp_tmf.index = cpu_to_le16(index); | ||
542 | |||
543 | res = asd_enqueue_internal(ascb, asd_tmf_tasklet_complete, | ||
544 | asd_tmf_timedout); | ||
545 | if (res) | ||
546 | goto out_err; | ||
547 | wait_for_completion(&ascb->completion); | ||
548 | res = (int) (unsigned long) ascb->uldd_task; | ||
549 | |||
550 | switch (res) { | ||
551 | case TC_NO_ERROR + 0xFF00: | ||
552 | res = TMF_RESP_FUNC_COMPLETE; | ||
553 | break; | ||
554 | case TF_NAK_RECV + 0xFF00: | ||
555 | res = TMF_RESP_INVALID_FRAME; | ||
556 | break; | ||
557 | case TF_TMF_TASK_DONE + 0xFF00: | ||
558 | res = TMF_RESP_FUNC_FAILED; | ||
559 | break; | ||
560 | case TF_TMF_NO_TAG + 0xFF00: | ||
561 | case TF_TMF_TAG_FREE + 0xFF00: /* the tag is in the free list */ | ||
562 | case TF_TMF_NO_CONN_HANDLE + 0xFF00: /* no such device */ | ||
563 | res = TMF_RESP_FUNC_COMPLETE; | ||
564 | break; | ||
565 | case TF_TMF_NO_CTX + 0xFF00: /* not in seq, or proto != SSP */ | ||
566 | res = TMF_RESP_FUNC_ESUPP; | ||
567 | break; | ||
568 | default: | ||
569 | ASD_DPRINTK("%s: converting result 0x%x to TMF_RESP_FUNC_FAILED\n", | ||
570 | __FUNCTION__, res); | ||
571 | res = TMF_RESP_FUNC_FAILED; | ||
572 | break; | ||
573 | } | ||
574 | out_err: | ||
575 | asd_ascb_free(ascb); | ||
576 | return res; | ||
577 | } | ||
578 | |||
579 | int asd_abort_task_set(struct domain_device *dev, u8 *lun) | ||
580 | { | ||
581 | int res = asd_initiate_ssp_tmf(dev, lun, TMF_ABORT_TASK_SET, 0); | ||
582 | |||
583 | if (res == TMF_RESP_FUNC_COMPLETE) | ||
584 | asd_clear_nexus_I_T_L(dev, lun); | ||
585 | return res; | ||
586 | } | ||
587 | |||
588 | int asd_clear_aca(struct domain_device *dev, u8 *lun) | ||
589 | { | ||
590 | int res = asd_initiate_ssp_tmf(dev, lun, TMF_CLEAR_ACA, 0); | ||
591 | |||
592 | if (res == TMF_RESP_FUNC_COMPLETE) | ||
593 | asd_clear_nexus_I_T_L(dev, lun); | ||
594 | return res; | ||
595 | } | ||
596 | |||
597 | int asd_clear_task_set(struct domain_device *dev, u8 *lun) | ||
598 | { | ||
599 | int res = asd_initiate_ssp_tmf(dev, lun, TMF_CLEAR_TASK_SET, 0); | ||
600 | |||
601 | if (res == TMF_RESP_FUNC_COMPLETE) | ||
602 | asd_clear_nexus_I_T_L(dev, lun); | ||
603 | return res; | ||
604 | } | ||
605 | |||
606 | int asd_lu_reset(struct domain_device *dev, u8 *lun) | ||
607 | { | ||
608 | int res = asd_initiate_ssp_tmf(dev, lun, TMF_LU_RESET, 0); | ||
609 | |||
610 | if (res == TMF_RESP_FUNC_COMPLETE) | ||
611 | asd_clear_nexus_I_T_L(dev, lun); | ||
612 | return res; | ||
613 | } | ||
614 | |||
615 | /** | ||
616 | * asd_query_task -- send a QUERY TASK TMF to an I_T_L_Q nexus | ||
617 | * task: pointer to sas_task struct of interest | ||
618 | * | ||
619 | * Returns: TMF_RESP_FUNC_COMPLETE if the task is not in the task set, | ||
620 | * or TMF_RESP_FUNC_SUCC if the task is in the task set. | ||
621 | * | ||
622 | * Normally the management layer sets the task to aborted state, | ||
623 | * and then calls query task and then abort task. | ||
624 | */ | ||
625 | int asd_query_task(struct sas_task *task) | ||
626 | { | ||
627 | struct asd_ascb *ascb = task->lldd_task; | ||
628 | int index; | ||
629 | |||
630 | if (ascb) { | ||
631 | index = ascb->tc_index; | ||
632 | return asd_initiate_ssp_tmf(task->dev, task->ssp_task.LUN, | ||
633 | TMF_QUERY_TASK, index); | ||
634 | } | ||
635 | return TMF_RESP_FUNC_COMPLETE; | ||
636 | } | ||
diff --git a/drivers/scsi/libsas/Kconfig b/drivers/scsi/libsas/Kconfig new file mode 100644 index 000000000000..aafdc92f8312 --- /dev/null +++ b/drivers/scsi/libsas/Kconfig | |||
@@ -0,0 +1,39 @@ | |||
1 | # | ||
2 | # Kernel configuration file for the SAS Class | ||
3 | # | ||
4 | # Copyright (C) 2005 Adaptec, Inc. All rights reserved. | ||
5 | # Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> | ||
6 | # | ||
7 | # This file is licensed under GPLv2. | ||
8 | # | ||
9 | # This program is free software; you can redistribute it and/or | ||
10 | # modify it under the terms of the GNU General Public License as | ||
11 | # published by the Free Software Foundation; version 2 of the | ||
12 | # License. | ||
13 | # | ||
14 | # This program is distributed in the hope that it will be useful, | ||
15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | # General Public License for more details. | ||
18 | # | ||
19 | # You should have received a copy of the GNU General Public License | ||
20 | # along with this program; if not, write to the Free Software | ||
21 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | ||
22 | # USA | ||
23 | # | ||
24 | |||
25 | config SCSI_SAS_LIBSAS | ||
26 | tristate "SAS Domain Transport Attributes" | ||
27 | depends on SCSI | ||
28 | select SCSI_SAS_ATTRS | ||
29 | help | ||
30 | This provides transport specific helpers for SAS drivers which | ||
31 | use the domain device construct (like the aic94xxx). | ||
32 | |||
33 | config SCSI_SAS_LIBSAS_DEBUG | ||
34 | bool "Compile the SAS Domain Transport Attributes in debug mode" | ||
35 | default y | ||
36 | depends on SCSI_SAS_LIBSAS | ||
37 | help | ||
38 | Compiles the SAS Layer in debug mode. In debug mode, the | ||
39 | SAS Layer prints diagnostic and debug messages. | ||
diff --git a/drivers/scsi/libsas/Makefile b/drivers/scsi/libsas/Makefile new file mode 100644 index 000000000000..44d972a3b4bd --- /dev/null +++ b/drivers/scsi/libsas/Makefile | |||
@@ -0,0 +1,36 @@ | |||
1 | # | ||
2 | # Kernel Makefile for the libsas helpers | ||
3 | # | ||
4 | # Copyright (C) 2005 Adaptec, Inc. All rights reserved. | ||
5 | # Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> | ||
6 | # | ||
7 | # This file is licensed under GPLv2. | ||
8 | # | ||
9 | # This program is free software; you can redistribute it and/or | ||
10 | # modify it under the terms of the GNU General Public License as | ||
11 | # published by the Free Software Foundation; version 2 of the | ||
12 | # License. | ||
13 | # | ||
14 | # This program is distributed in the hope that it will be useful, | ||
15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | # General Public License for more details. | ||
18 | # | ||
19 | # You should have received a copy of the GNU General Public License | ||
20 | # along with this program; if not, write to the Free Software | ||
21 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | ||
22 | # USA | ||
23 | |||
24 | ifeq ($(CONFIG_SCSI_SAS_LIBSAS_DEBUG),y) | ||
25 | EXTRA_CFLAGS += -DSAS_DEBUG | ||
26 | endif | ||
27 | |||
28 | obj-$(CONFIG_SCSI_SAS_LIBSAS) += libsas.o | ||
29 | libsas-y += sas_init.o \ | ||
30 | sas_phy.o \ | ||
31 | sas_port.o \ | ||
32 | sas_event.o \ | ||
33 | sas_dump.o \ | ||
34 | sas_discover.o \ | ||
35 | sas_expander.o \ | ||
36 | sas_scsi_host.o | ||
diff --git a/drivers/scsi/libsas/sas_discover.c b/drivers/scsi/libsas/sas_discover.c new file mode 100644 index 000000000000..d977bd492d8d --- /dev/null +++ b/drivers/scsi/libsas/sas_discover.c | |||
@@ -0,0 +1,749 @@ | |||
1 | /* | ||
2 | * Serial Attached SCSI (SAS) Discover process | ||
3 | * | ||
4 | * Copyright (C) 2005 Adaptec, Inc. All rights reserved. | ||
5 | * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> | ||
6 | * | ||
7 | * This file is licensed under GPLv2. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License as | ||
11 | * published by the Free Software Foundation; either version 2 of the | ||
12 | * License, or (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #include <linux/pci.h> | ||
26 | #include <linux/scatterlist.h> | ||
27 | #include <scsi/scsi_host.h> | ||
28 | #include <scsi/scsi_eh.h> | ||
29 | #include "sas_internal.h" | ||
30 | |||
31 | #include <scsi/scsi_transport.h> | ||
32 | #include <scsi/scsi_transport_sas.h> | ||
33 | #include "../scsi_sas_internal.h" | ||
34 | |||
35 | /* ---------- Basic task processing for discovery purposes ---------- */ | ||
36 | |||
37 | void sas_init_dev(struct domain_device *dev) | ||
38 | { | ||
39 | INIT_LIST_HEAD(&dev->siblings); | ||
40 | INIT_LIST_HEAD(&dev->dev_list_node); | ||
41 | switch (dev->dev_type) { | ||
42 | case SAS_END_DEV: | ||
43 | break; | ||
44 | case EDGE_DEV: | ||
45 | case FANOUT_DEV: | ||
46 | INIT_LIST_HEAD(&dev->ex_dev.children); | ||
47 | break; | ||
48 | case SATA_DEV: | ||
49 | case SATA_PM: | ||
50 | case SATA_PM_PORT: | ||
51 | INIT_LIST_HEAD(&dev->sata_dev.children); | ||
52 | break; | ||
53 | default: | ||
54 | break; | ||
55 | } | ||
56 | } | ||
57 | |||
58 | static void sas_task_timedout(unsigned long _task) | ||
59 | { | ||
60 | struct sas_task *task = (void *) _task; | ||
61 | unsigned long flags; | ||
62 | |||
63 | spin_lock_irqsave(&task->task_state_lock, flags); | ||
64 | if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) | ||
65 | task->task_state_flags |= SAS_TASK_STATE_ABORTED; | ||
66 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
67 | |||
68 | complete(&task->completion); | ||
69 | } | ||
70 | |||
71 | static void sas_disc_task_done(struct sas_task *task) | ||
72 | { | ||
73 | if (!del_timer(&task->timer)) | ||
74 | return; | ||
75 | complete(&task->completion); | ||
76 | } | ||
77 | |||
78 | #define SAS_DEV_TIMEOUT 10 | ||
79 | |||
80 | /** | ||
81 | * sas_execute_task -- Basic task processing for discovery | ||
82 | * @task: the task to be executed | ||
83 | * @buffer: pointer to buffer to do I/O | ||
84 | * @size: size of @buffer | ||
85 | * @pci_dma_dir: PCI_DMA_... | ||
86 | */ | ||
87 | static int sas_execute_task(struct sas_task *task, void *buffer, int size, | ||
88 | int pci_dma_dir) | ||
89 | { | ||
90 | int res = 0; | ||
91 | struct scatterlist *scatter = NULL; | ||
92 | struct task_status_struct *ts = &task->task_status; | ||
93 | int num_scatter = 0; | ||
94 | int retries = 0; | ||
95 | struct sas_internal *i = | ||
96 | to_sas_internal(task->dev->port->ha->core.shost->transportt); | ||
97 | |||
98 | if (pci_dma_dir != PCI_DMA_NONE) { | ||
99 | scatter = kzalloc(sizeof(*scatter), GFP_KERNEL); | ||
100 | if (!scatter) | ||
101 | goto out; | ||
102 | |||
103 | sg_init_one(scatter, buffer, size); | ||
104 | num_scatter = 1; | ||
105 | } | ||
106 | |||
107 | task->task_proto = task->dev->tproto; | ||
108 | task->scatter = scatter; | ||
109 | task->num_scatter = num_scatter; | ||
110 | task->total_xfer_len = size; | ||
111 | task->data_dir = pci_dma_dir; | ||
112 | task->task_done = sas_disc_task_done; | ||
113 | |||
114 | for (retries = 0; retries < 5; retries++) { | ||
115 | task->task_state_flags = SAS_TASK_STATE_PENDING; | ||
116 | init_completion(&task->completion); | ||
117 | |||
118 | task->timer.data = (unsigned long) task; | ||
119 | task->timer.function = sas_task_timedout; | ||
120 | task->timer.expires = jiffies + SAS_DEV_TIMEOUT*HZ; | ||
121 | add_timer(&task->timer); | ||
122 | |||
123 | res = i->dft->lldd_execute_task(task, 1, GFP_KERNEL); | ||
124 | if (res) { | ||
125 | del_timer(&task->timer); | ||
126 | SAS_DPRINTK("executing SAS discovery task failed:%d\n", | ||
127 | res); | ||
128 | goto ex_err; | ||
129 | } | ||
130 | wait_for_completion(&task->completion); | ||
131 | res = -ETASK; | ||
132 | if (task->task_state_flags & SAS_TASK_STATE_ABORTED) { | ||
133 | int res2; | ||
134 | SAS_DPRINTK("task aborted, flags:0x%x\n", | ||
135 | task->task_state_flags); | ||
136 | res2 = i->dft->lldd_abort_task(task); | ||
137 | SAS_DPRINTK("came back from abort task\n"); | ||
138 | if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { | ||
139 | if (res2 == TMF_RESP_FUNC_COMPLETE) | ||
140 | continue; /* Retry the task */ | ||
141 | else | ||
142 | goto ex_err; | ||
143 | } | ||
144 | } | ||
145 | if (task->task_status.stat == SAM_BUSY || | ||
146 | task->task_status.stat == SAM_TASK_SET_FULL || | ||
147 | task->task_status.stat == SAS_QUEUE_FULL) { | ||
148 | SAS_DPRINTK("task: q busy, sleeping...\n"); | ||
149 | schedule_timeout_interruptible(HZ); | ||
150 | } else if (task->task_status.stat == SAM_CHECK_COND) { | ||
151 | struct scsi_sense_hdr shdr; | ||
152 | |||
153 | if (!scsi_normalize_sense(ts->buf, ts->buf_valid_size, | ||
154 | &shdr)) { | ||
155 | SAS_DPRINTK("couldn't normalize sense\n"); | ||
156 | continue; | ||
157 | } | ||
158 | if ((shdr.sense_key == 6 && shdr.asc == 0x29) || | ||
159 | (shdr.sense_key == 2 && shdr.asc == 4 && | ||
160 | shdr.ascq == 1)) { | ||
161 | SAS_DPRINTK("device %016llx LUN: %016llx " | ||
162 | "powering up or not ready yet, " | ||
163 | "sleeping...\n", | ||
164 | SAS_ADDR(task->dev->sas_addr), | ||
165 | SAS_ADDR(task->ssp_task.LUN)); | ||
166 | |||
167 | schedule_timeout_interruptible(5*HZ); | ||
168 | } else if (shdr.sense_key == 1) { | ||
169 | res = 0; | ||
170 | break; | ||
171 | } else if (shdr.sense_key == 5) { | ||
172 | break; | ||
173 | } else { | ||
174 | SAS_DPRINTK("dev %016llx LUN: %016llx " | ||
175 | "sense key:0x%x ASC:0x%x ASCQ:0x%x" | ||
176 | "\n", | ||
177 | SAS_ADDR(task->dev->sas_addr), | ||
178 | SAS_ADDR(task->ssp_task.LUN), | ||
179 | shdr.sense_key, | ||
180 | shdr.asc, shdr.ascq); | ||
181 | } | ||
182 | } else if (task->task_status.resp != SAS_TASK_COMPLETE || | ||
183 | task->task_status.stat != SAM_GOOD) { | ||
184 | SAS_DPRINTK("task finished with resp:0x%x, " | ||
185 | "stat:0x%x\n", | ||
186 | task->task_status.resp, | ||
187 | task->task_status.stat); | ||
188 | goto ex_err; | ||
189 | } else { | ||
190 | res = 0; | ||
191 | break; | ||
192 | } | ||
193 | } | ||
194 | ex_err: | ||
195 | if (pci_dma_dir != PCI_DMA_NONE) | ||
196 | kfree(scatter); | ||
197 | out: | ||
198 | return res; | ||
199 | } | ||
200 | |||
201 | /* ---------- Domain device discovery ---------- */ | ||
202 | |||
203 | /** | ||
204 | * sas_get_port_device -- Discover devices which caused port creation | ||
205 | * @port: pointer to struct sas_port of interest | ||
206 | * | ||
207 | * Devices directly attached to a HA port, have no parent. This is | ||
208 | * how we know they are (domain) "root" devices. All other devices | ||
209 | * do, and should have their "parent" pointer set appropriately as | ||
210 | * soon as a child device is discovered. | ||
211 | */ | ||
212 | static int sas_get_port_device(struct asd_sas_port *port) | ||
213 | { | ||
214 | unsigned long flags; | ||
215 | struct asd_sas_phy *phy; | ||
216 | struct sas_rphy *rphy; | ||
217 | struct domain_device *dev; | ||
218 | |||
219 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | ||
220 | if (!dev) | ||
221 | return -ENOMEM; | ||
222 | |||
223 | spin_lock_irqsave(&port->phy_list_lock, flags); | ||
224 | if (list_empty(&port->phy_list)) { | ||
225 | spin_unlock_irqrestore(&port->phy_list_lock, flags); | ||
226 | kfree(dev); | ||
227 | return -ENODEV; | ||
228 | } | ||
229 | phy = container_of(port->phy_list.next, struct asd_sas_phy, port_phy_el); | ||
230 | spin_lock(&phy->frame_rcvd_lock); | ||
231 | memcpy(dev->frame_rcvd, phy->frame_rcvd, min(sizeof(dev->frame_rcvd), | ||
232 | (size_t)phy->frame_rcvd_size)); | ||
233 | spin_unlock(&phy->frame_rcvd_lock); | ||
234 | spin_unlock_irqrestore(&port->phy_list_lock, flags); | ||
235 | |||
236 | if (dev->frame_rcvd[0] == 0x34 && port->oob_mode == SATA_OOB_MODE) { | ||
237 | struct dev_to_host_fis *fis = | ||
238 | (struct dev_to_host_fis *) dev->frame_rcvd; | ||
239 | if (fis->interrupt_reason == 1 && fis->lbal == 1 && | ||
240 | fis->byte_count_low==0x69 && fis->byte_count_high == 0x96 | ||
241 | && (fis->device & ~0x10) == 0) | ||
242 | dev->dev_type = SATA_PM; | ||
243 | else | ||
244 | dev->dev_type = SATA_DEV; | ||
245 | dev->tproto = SATA_PROTO; | ||
246 | } else { | ||
247 | struct sas_identify_frame *id = | ||
248 | (struct sas_identify_frame *) dev->frame_rcvd; | ||
249 | dev->dev_type = id->dev_type; | ||
250 | dev->iproto = id->initiator_bits; | ||
251 | dev->tproto = id->target_bits; | ||
252 | } | ||
253 | |||
254 | sas_init_dev(dev); | ||
255 | |||
256 | switch (dev->dev_type) { | ||
257 | case SAS_END_DEV: | ||
258 | rphy = sas_end_device_alloc(port->port); | ||
259 | break; | ||
260 | case EDGE_DEV: | ||
261 | rphy = sas_expander_alloc(port->port, | ||
262 | SAS_EDGE_EXPANDER_DEVICE); | ||
263 | break; | ||
264 | case FANOUT_DEV: | ||
265 | rphy = sas_expander_alloc(port->port, | ||
266 | SAS_FANOUT_EXPANDER_DEVICE); | ||
267 | break; | ||
268 | case SATA_DEV: | ||
269 | default: | ||
270 | printk("ERROR: Unidentified device type %d\n", dev->dev_type); | ||
271 | rphy = NULL; | ||
272 | break; | ||
273 | } | ||
274 | |||
275 | if (!rphy) { | ||
276 | kfree(dev); | ||
277 | return -ENODEV; | ||
278 | } | ||
279 | rphy->identify.phy_identifier = phy->phy->identify.phy_identifier; | ||
280 | memcpy(dev->sas_addr, port->attached_sas_addr, SAS_ADDR_SIZE); | ||
281 | sas_fill_in_rphy(dev, rphy); | ||
282 | sas_hash_addr(dev->hashed_sas_addr, dev->sas_addr); | ||
283 | port->port_dev = dev; | ||
284 | dev->port = port; | ||
285 | dev->linkrate = port->linkrate; | ||
286 | dev->min_linkrate = port->linkrate; | ||
287 | dev->max_linkrate = port->linkrate; | ||
288 | dev->pathways = port->num_phys; | ||
289 | memset(port->disc.fanout_sas_addr, 0, SAS_ADDR_SIZE); | ||
290 | memset(port->disc.eeds_a, 0, SAS_ADDR_SIZE); | ||
291 | memset(port->disc.eeds_b, 0, SAS_ADDR_SIZE); | ||
292 | port->disc.max_level = 0; | ||
293 | |||
294 | dev->rphy = rphy; | ||
295 | spin_lock(&port->dev_list_lock); | ||
296 | list_add_tail(&dev->dev_list_node, &port->dev_list); | ||
297 | spin_unlock(&port->dev_list_lock); | ||
298 | |||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | /* ---------- Discover and Revalidate ---------- */ | ||
303 | |||
304 | /* ---------- SATA ---------- */ | ||
305 | |||
306 | static void sas_get_ata_command_set(struct domain_device *dev) | ||
307 | { | ||
308 | struct dev_to_host_fis *fis = | ||
309 | (struct dev_to_host_fis *) dev->frame_rcvd; | ||
310 | |||
311 | if ((fis->sector_count == 1 && /* ATA */ | ||
312 | fis->lbal == 1 && | ||
313 | fis->lbam == 0 && | ||
314 | fis->lbah == 0 && | ||
315 | fis->device == 0) | ||
316 | || | ||
317 | (fis->sector_count == 0 && /* CE-ATA (mATA) */ | ||
318 | fis->lbal == 0 && | ||
319 | fis->lbam == 0xCE && | ||
320 | fis->lbah == 0xAA && | ||
321 | (fis->device & ~0x10) == 0)) | ||
322 | |||
323 | dev->sata_dev.command_set = ATA_COMMAND_SET; | ||
324 | |||
325 | else if ((fis->interrupt_reason == 1 && /* ATAPI */ | ||
326 | fis->lbal == 1 && | ||
327 | fis->byte_count_low == 0x14 && | ||
328 | fis->byte_count_high == 0xEB && | ||
329 | (fis->device & ~0x10) == 0)) | ||
330 | |||
331 | dev->sata_dev.command_set = ATAPI_COMMAND_SET; | ||
332 | |||
333 | else if ((fis->sector_count == 1 && /* SEMB */ | ||
334 | fis->lbal == 1 && | ||
335 | fis->lbam == 0x3C && | ||
336 | fis->lbah == 0xC3 && | ||
337 | fis->device == 0) | ||
338 | || | ||
339 | (fis->interrupt_reason == 1 && /* SATA PM */ | ||
340 | fis->lbal == 1 && | ||
341 | fis->byte_count_low == 0x69 && | ||
342 | fis->byte_count_high == 0x96 && | ||
343 | (fis->device & ~0x10) == 0)) | ||
344 | |||
345 | /* Treat it as a superset? */ | ||
346 | dev->sata_dev.command_set = ATAPI_COMMAND_SET; | ||
347 | } | ||
348 | |||
349 | /** | ||
350 | * sas_issue_ata_cmd -- Basic SATA command processing for discovery | ||
351 | * @dev: the device to send the command to | ||
352 | * @command: the command register | ||
353 | * @features: the features register | ||
354 | * @buffer: pointer to buffer to do I/O | ||
355 | * @size: size of @buffer | ||
356 | * @pci_dma_dir: PCI_DMA_... | ||
357 | */ | ||
358 | static int sas_issue_ata_cmd(struct domain_device *dev, u8 command, | ||
359 | u8 features, void *buffer, int size, | ||
360 | int pci_dma_dir) | ||
361 | { | ||
362 | int res = 0; | ||
363 | struct sas_task *task; | ||
364 | struct dev_to_host_fis *d2h_fis = (struct dev_to_host_fis *) | ||
365 | &dev->frame_rcvd[0]; | ||
366 | |||
367 | res = -ENOMEM; | ||
368 | task = sas_alloc_task(GFP_KERNEL); | ||
369 | if (!task) | ||
370 | goto out; | ||
371 | |||
372 | task->dev = dev; | ||
373 | |||
374 | task->ata_task.fis.command = command; | ||
375 | task->ata_task.fis.features = features; | ||
376 | task->ata_task.fis.device = d2h_fis->device; | ||
377 | task->ata_task.retry_count = 1; | ||
378 | |||
379 | res = sas_execute_task(task, buffer, size, pci_dma_dir); | ||
380 | |||
381 | sas_free_task(task); | ||
382 | out: | ||
383 | return res; | ||
384 | } | ||
385 | |||
386 | static void sas_sata_propagate_sas_addr(struct domain_device *dev) | ||
387 | { | ||
388 | unsigned long flags; | ||
389 | struct asd_sas_port *port = dev->port; | ||
390 | struct asd_sas_phy *phy; | ||
391 | |||
392 | BUG_ON(dev->parent); | ||
393 | |||
394 | memcpy(port->attached_sas_addr, dev->sas_addr, SAS_ADDR_SIZE); | ||
395 | spin_lock_irqsave(&port->phy_list_lock, flags); | ||
396 | list_for_each_entry(phy, &port->phy_list, port_phy_el) | ||
397 | memcpy(phy->attached_sas_addr, dev->sas_addr, SAS_ADDR_SIZE); | ||
398 | spin_unlock_irqrestore(&port->phy_list_lock, flags); | ||
399 | } | ||
400 | |||
401 | #define ATA_IDENTIFY_DEV 0xEC | ||
402 | #define ATA_IDENTIFY_PACKET_DEV 0xA1 | ||
403 | #define ATA_SET_FEATURES 0xEF | ||
404 | #define ATA_FEATURE_PUP_STBY_SPIN_UP 0x07 | ||
405 | |||
406 | /** | ||
407 | * sas_discover_sata_dev -- discover a STP/SATA device (SATA_DEV) | ||
408 | * @dev: STP/SATA device of interest (ATA/ATAPI) | ||
409 | * | ||
410 | * The LLDD has already been notified of this device, so that we can | ||
411 | * send FISes to it. Here we try to get IDENTIFY DEVICE or IDENTIFY | ||
412 | * PACKET DEVICE, if ATAPI device, so that the LLDD can fine-tune its | ||
413 | * performance for this device. | ||
414 | */ | ||
415 | static int sas_discover_sata_dev(struct domain_device *dev) | ||
416 | { | ||
417 | int res; | ||
418 | __le16 *identify_x; | ||
419 | u8 command; | ||
420 | |||
421 | identify_x = kzalloc(512, GFP_KERNEL); | ||
422 | if (!identify_x) | ||
423 | return -ENOMEM; | ||
424 | |||
425 | if (dev->sata_dev.command_set == ATA_COMMAND_SET) { | ||
426 | dev->sata_dev.identify_device = identify_x; | ||
427 | command = ATA_IDENTIFY_DEV; | ||
428 | } else { | ||
429 | dev->sata_dev.identify_packet_device = identify_x; | ||
430 | command = ATA_IDENTIFY_PACKET_DEV; | ||
431 | } | ||
432 | |||
433 | res = sas_issue_ata_cmd(dev, command, 0, identify_x, 512, | ||
434 | PCI_DMA_FROMDEVICE); | ||
435 | if (res) | ||
436 | goto out_err; | ||
437 | |||
438 | /* lives on the media? */ | ||
439 | if (le16_to_cpu(identify_x[0]) & 4) { | ||
440 | /* incomplete response */ | ||
441 | SAS_DPRINTK("sending SET FEATURE/PUP_STBY_SPIN_UP to " | ||
442 | "dev %llx\n", SAS_ADDR(dev->sas_addr)); | ||
443 | if (!le16_to_cpu(identify_x[83] & (1<<6))) | ||
444 | goto cont1; | ||
445 | res = sas_issue_ata_cmd(dev, ATA_SET_FEATURES, | ||
446 | ATA_FEATURE_PUP_STBY_SPIN_UP, | ||
447 | NULL, 0, PCI_DMA_NONE); | ||
448 | if (res) | ||
449 | goto cont1; | ||
450 | |||
451 | schedule_timeout_interruptible(5*HZ); /* More time? */ | ||
452 | res = sas_issue_ata_cmd(dev, command, 0, identify_x, 512, | ||
453 | PCI_DMA_FROMDEVICE); | ||
454 | if (res) | ||
455 | goto out_err; | ||
456 | } | ||
457 | cont1: | ||
458 | /* Get WWN */ | ||
459 | if (dev->port->oob_mode != SATA_OOB_MODE) { | ||
460 | memcpy(dev->sas_addr, dev->sata_dev.rps_resp.rps.stp_sas_addr, | ||
461 | SAS_ADDR_SIZE); | ||
462 | } else if (dev->sata_dev.command_set == ATA_COMMAND_SET && | ||
463 | (le16_to_cpu(dev->sata_dev.identify_device[108]) & 0xF000) | ||
464 | == 0x5000) { | ||
465 | int i; | ||
466 | |||
467 | for (i = 0; i < 4; i++) { | ||
468 | dev->sas_addr[2*i] = | ||
469 | (le16_to_cpu(dev->sata_dev.identify_device[108+i]) & 0xFF00) >> 8; | ||
470 | dev->sas_addr[2*i+1] = | ||
471 | le16_to_cpu(dev->sata_dev.identify_device[108+i]) & 0x00FF; | ||
472 | } | ||
473 | } | ||
474 | sas_hash_addr(dev->hashed_sas_addr, dev->sas_addr); | ||
475 | if (!dev->parent) | ||
476 | sas_sata_propagate_sas_addr(dev); | ||
477 | |||
478 | /* XXX Hint: register this SATA device with SATL. | ||
479 | When this returns, dev->sata_dev->lu is alive and | ||
480 | present. | ||
481 | sas_satl_register_dev(dev); | ||
482 | */ | ||
483 | return 0; | ||
484 | out_err: | ||
485 | dev->sata_dev.identify_packet_device = NULL; | ||
486 | dev->sata_dev.identify_device = NULL; | ||
487 | kfree(identify_x); | ||
488 | return res; | ||
489 | } | ||
490 | |||
491 | static int sas_discover_sata_pm(struct domain_device *dev) | ||
492 | { | ||
493 | return -ENODEV; | ||
494 | } | ||
495 | |||
496 | int sas_notify_lldd_dev_found(struct domain_device *dev) | ||
497 | { | ||
498 | int res = 0; | ||
499 | struct sas_ha_struct *sas_ha = dev->port->ha; | ||
500 | struct Scsi_Host *shost = sas_ha->core.shost; | ||
501 | struct sas_internal *i = to_sas_internal(shost->transportt); | ||
502 | |||
503 | if (i->dft->lldd_dev_found) { | ||
504 | res = i->dft->lldd_dev_found(dev); | ||
505 | if (res) { | ||
506 | printk("sas: driver on pcidev %s cannot handle " | ||
507 | "device %llx, error:%d\n", | ||
508 | pci_name(sas_ha->pcidev), | ||
509 | SAS_ADDR(dev->sas_addr), res); | ||
510 | } | ||
511 | } | ||
512 | return res; | ||
513 | } | ||
514 | |||
515 | |||
516 | void sas_notify_lldd_dev_gone(struct domain_device *dev) | ||
517 | { | ||
518 | struct sas_ha_struct *sas_ha = dev->port->ha; | ||
519 | struct Scsi_Host *shost = sas_ha->core.shost; | ||
520 | struct sas_internal *i = to_sas_internal(shost->transportt); | ||
521 | |||
522 | if (i->dft->lldd_dev_gone) | ||
523 | i->dft->lldd_dev_gone(dev); | ||
524 | } | ||
525 | |||
526 | /* ---------- Common/dispatchers ---------- */ | ||
527 | |||
528 | /** | ||
529 | * sas_discover_sata -- discover an STP/SATA domain device | ||
530 | * @dev: pointer to struct domain_device of interest | ||
531 | * | ||
532 | * First we notify the LLDD of this device, so we can send frames to | ||
533 | * it. Then depending on the type of device we call the appropriate | ||
534 | * discover functions. Once device discover is done, we notify the | ||
535 | * LLDD so that it can fine-tune its parameters for the device, by | ||
536 | * removing it and then adding it. That is, the second time around, | ||
537 | * the driver would have certain fields, that it is looking at, set. | ||
538 | * Finally we initialize the kobj so that the device can be added to | ||
539 | * the system at registration time. Devices directly attached to a HA | ||
540 | * port, have no parents. All other devices do, and should have their | ||
541 | * "parent" pointer set appropriately before calling this function. | ||
542 | */ | ||
543 | int sas_discover_sata(struct domain_device *dev) | ||
544 | { | ||
545 | int res; | ||
546 | |||
547 | sas_get_ata_command_set(dev); | ||
548 | |||
549 | res = sas_notify_lldd_dev_found(dev); | ||
550 | if (res) | ||
551 | return res; | ||
552 | |||
553 | switch (dev->dev_type) { | ||
554 | case SATA_DEV: | ||
555 | res = sas_discover_sata_dev(dev); | ||
556 | break; | ||
557 | case SATA_PM: | ||
558 | res = sas_discover_sata_pm(dev); | ||
559 | break; | ||
560 | default: | ||
561 | break; | ||
562 | } | ||
563 | |||
564 | sas_notify_lldd_dev_gone(dev); | ||
565 | if (!res) { | ||
566 | sas_notify_lldd_dev_found(dev); | ||
567 | } | ||
568 | return res; | ||
569 | } | ||
570 | |||
571 | /** | ||
572 | * sas_discover_end_dev -- discover an end device (SSP, etc) | ||
573 | * @end: pointer to domain device of interest | ||
574 | * | ||
575 | * See comment in sas_discover_sata(). | ||
576 | */ | ||
577 | int sas_discover_end_dev(struct domain_device *dev) | ||
578 | { | ||
579 | int res; | ||
580 | |||
581 | res = sas_notify_lldd_dev_found(dev); | ||
582 | if (res) | ||
583 | return res; | ||
584 | |||
585 | res = sas_rphy_add(dev->rphy); | ||
586 | if (res) | ||
587 | goto out_err; | ||
588 | |||
589 | /* do this to get the end device port attributes which will have | ||
590 | * been scanned in sas_rphy_add */ | ||
591 | sas_notify_lldd_dev_gone(dev); | ||
592 | sas_notify_lldd_dev_found(dev); | ||
593 | |||
594 | return 0; | ||
595 | |||
596 | out_err: | ||
597 | sas_notify_lldd_dev_gone(dev); | ||
598 | return res; | ||
599 | } | ||
600 | |||
601 | /* ---------- Device registration and unregistration ---------- */ | ||
602 | |||
603 | static inline void sas_unregister_common_dev(struct domain_device *dev) | ||
604 | { | ||
605 | sas_notify_lldd_dev_gone(dev); | ||
606 | if (!dev->parent) | ||
607 | dev->port->port_dev = NULL; | ||
608 | else | ||
609 | list_del_init(&dev->siblings); | ||
610 | list_del_init(&dev->dev_list_node); | ||
611 | } | ||
612 | |||
613 | void sas_unregister_dev(struct domain_device *dev) | ||
614 | { | ||
615 | if (dev->rphy) { | ||
616 | sas_remove_children(&dev->rphy->dev); | ||
617 | sas_rphy_delete(dev->rphy); | ||
618 | dev->rphy = NULL; | ||
619 | } | ||
620 | if (dev->dev_type == EDGE_DEV || dev->dev_type == FANOUT_DEV) { | ||
621 | /* remove the phys and ports, everything else should be gone */ | ||
622 | kfree(dev->ex_dev.ex_phy); | ||
623 | dev->ex_dev.ex_phy = NULL; | ||
624 | } | ||
625 | sas_unregister_common_dev(dev); | ||
626 | } | ||
627 | |||
628 | void sas_unregister_domain_devices(struct asd_sas_port *port) | ||
629 | { | ||
630 | struct domain_device *dev, *n; | ||
631 | |||
632 | list_for_each_entry_safe_reverse(dev,n,&port->dev_list,dev_list_node) | ||
633 | sas_unregister_dev(dev); | ||
634 | |||
635 | port->port->rphy = NULL; | ||
636 | |||
637 | } | ||
638 | |||
639 | /* ---------- Discovery and Revalidation ---------- */ | ||
640 | |||
641 | /** | ||
642 | * sas_discover_domain -- discover the domain | ||
643 | * @port: port to the domain of interest | ||
644 | * | ||
645 | * NOTE: this process _must_ quit (return) as soon as any connection | ||
646 | * errors are encountered. Connection recovery is done elsewhere. | ||
647 | * Discover process only interrogates devices in order to discover the | ||
648 | * domain. | ||
649 | */ | ||
650 | static void sas_discover_domain(void *data) | ||
651 | { | ||
652 | int error = 0; | ||
653 | struct asd_sas_port *port = data; | ||
654 | |||
655 | sas_begin_event(DISCE_DISCOVER_DOMAIN, &port->disc.disc_event_lock, | ||
656 | &port->disc.pending); | ||
657 | |||
658 | if (port->port_dev) | ||
659 | return ; | ||
660 | else { | ||
661 | error = sas_get_port_device(port); | ||
662 | if (error) | ||
663 | return; | ||
664 | } | ||
665 | |||
666 | SAS_DPRINTK("DOING DISCOVERY on port %d, pid:%d\n", port->id, | ||
667 | current->pid); | ||
668 | |||
669 | switch (port->port_dev->dev_type) { | ||
670 | case SAS_END_DEV: | ||
671 | error = sas_discover_end_dev(port->port_dev); | ||
672 | break; | ||
673 | case EDGE_DEV: | ||
674 | case FANOUT_DEV: | ||
675 | error = sas_discover_root_expander(port->port_dev); | ||
676 | break; | ||
677 | case SATA_DEV: | ||
678 | case SATA_PM: | ||
679 | error = sas_discover_sata(port->port_dev); | ||
680 | break; | ||
681 | default: | ||
682 | SAS_DPRINTK("unhandled device %d\n", port->port_dev->dev_type); | ||
683 | break; | ||
684 | } | ||
685 | |||
686 | if (error) { | ||
687 | kfree(port->port_dev); /* not kobject_register-ed yet */ | ||
688 | port->port_dev = NULL; | ||
689 | } | ||
690 | |||
691 | SAS_DPRINTK("DONE DISCOVERY on port %d, pid:%d, result:%d\n", port->id, | ||
692 | current->pid, error); | ||
693 | } | ||
694 | |||
695 | static void sas_revalidate_domain(void *data) | ||
696 | { | ||
697 | int res = 0; | ||
698 | struct asd_sas_port *port = data; | ||
699 | |||
700 | sas_begin_event(DISCE_REVALIDATE_DOMAIN, &port->disc.disc_event_lock, | ||
701 | &port->disc.pending); | ||
702 | |||
703 | SAS_DPRINTK("REVALIDATING DOMAIN on port %d, pid:%d\n", port->id, | ||
704 | current->pid); | ||
705 | if (port->port_dev) | ||
706 | res = sas_ex_revalidate_domain(port->port_dev); | ||
707 | |||
708 | SAS_DPRINTK("done REVALIDATING DOMAIN on port %d, pid:%d, res 0x%x\n", | ||
709 | port->id, current->pid, res); | ||
710 | } | ||
711 | |||
712 | /* ---------- Events ---------- */ | ||
713 | |||
714 | int sas_discover_event(struct asd_sas_port *port, enum discover_event ev) | ||
715 | { | ||
716 | struct sas_discovery *disc; | ||
717 | |||
718 | if (!port) | ||
719 | return 0; | ||
720 | disc = &port->disc; | ||
721 | |||
722 | BUG_ON(ev >= DISC_NUM_EVENTS); | ||
723 | |||
724 | sas_queue_event(ev, &disc->disc_event_lock, &disc->pending, | ||
725 | &disc->disc_work[ev], port->ha->core.shost); | ||
726 | |||
727 | return 0; | ||
728 | } | ||
729 | |||
730 | /** | ||
731 | * sas_init_disc -- initialize the discovery struct in the port | ||
732 | * @port: pointer to struct port | ||
733 | * | ||
734 | * Called when the ports are being initialized. | ||
735 | */ | ||
736 | void sas_init_disc(struct sas_discovery *disc, struct asd_sas_port *port) | ||
737 | { | ||
738 | int i; | ||
739 | |||
740 | static void (*sas_event_fns[DISC_NUM_EVENTS])(void *) = { | ||
741 | [DISCE_DISCOVER_DOMAIN] = sas_discover_domain, | ||
742 | [DISCE_REVALIDATE_DOMAIN] = sas_revalidate_domain, | ||
743 | }; | ||
744 | |||
745 | spin_lock_init(&disc->disc_event_lock); | ||
746 | disc->pending = 0; | ||
747 | for (i = 0; i < DISC_NUM_EVENTS; i++) | ||
748 | INIT_WORK(&disc->disc_work[i], sas_event_fns[i], port); | ||
749 | } | ||
diff --git a/drivers/scsi/libsas/sas_dump.c b/drivers/scsi/libsas/sas_dump.c new file mode 100644 index 000000000000..f1246d2c9bef --- /dev/null +++ b/drivers/scsi/libsas/sas_dump.c | |||
@@ -0,0 +1,76 @@ | |||
1 | /* | ||
2 | * Serial Attached SCSI (SAS) Dump/Debugging routines | ||
3 | * | ||
4 | * Copyright (C) 2005 Adaptec, Inc. All rights reserved. | ||
5 | * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> | ||
6 | * | ||
7 | * This file is licensed under GPLv2. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License as | ||
11 | * published by the Free Software Foundation; either version 2 of the | ||
12 | * License, or (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #include "sas_dump.h" | ||
26 | |||
27 | #ifdef SAS_DEBUG | ||
28 | |||
29 | static const char *sas_hae_str[] = { | ||
30 | [0] = "HAE_RESET", | ||
31 | }; | ||
32 | |||
33 | static const char *sas_porte_str[] = { | ||
34 | [0] = "PORTE_BYTES_DMAED", | ||
35 | [1] = "PORTE_BROADCAST_RCVD", | ||
36 | [2] = "PORTE_LINK_RESET_ERR", | ||
37 | [3] = "PORTE_TIMER_EVENT", | ||
38 | [4] = "PORTE_HARD_RESET", | ||
39 | }; | ||
40 | |||
41 | static const char *sas_phye_str[] = { | ||
42 | [0] = "PHYE_LOSS_OF_SIGNAL", | ||
43 | [1] = "PHYE_OOB_DONE", | ||
44 | [2] = "PHYE_OOB_ERROR", | ||
45 | [3] = "PHYE_SPINUP_HOLD", | ||
46 | }; | ||
47 | |||
48 | void sas_dprint_porte(int phyid, enum port_event pe) | ||
49 | { | ||
50 | SAS_DPRINTK("phy%d: port event: %s\n", phyid, sas_porte_str[pe]); | ||
51 | } | ||
52 | void sas_dprint_phye(int phyid, enum phy_event pe) | ||
53 | { | ||
54 | SAS_DPRINTK("phy%d: phy event: %s\n", phyid, sas_phye_str[pe]); | ||
55 | } | ||
56 | |||
57 | void sas_dprint_hae(struct sas_ha_struct *sas_ha, enum ha_event he) | ||
58 | { | ||
59 | SAS_DPRINTK("ha %s: %s event\n", pci_name(sas_ha->pcidev), | ||
60 | sas_hae_str[he]); | ||
61 | } | ||
62 | |||
63 | void sas_dump_port(struct asd_sas_port *port) | ||
64 | { | ||
65 | SAS_DPRINTK("port%d: class:0x%x\n", port->id, port->class); | ||
66 | SAS_DPRINTK("port%d: sas_addr:%llx\n", port->id, | ||
67 | SAS_ADDR(port->sas_addr)); | ||
68 | SAS_DPRINTK("port%d: attached_sas_addr:%llx\n", port->id, | ||
69 | SAS_ADDR(port->attached_sas_addr)); | ||
70 | SAS_DPRINTK("port%d: iproto:0x%x\n", port->id, port->iproto); | ||
71 | SAS_DPRINTK("port%d: tproto:0x%x\n", port->id, port->tproto); | ||
72 | SAS_DPRINTK("port%d: oob_mode:0x%x\n", port->id, port->oob_mode); | ||
73 | SAS_DPRINTK("port%d: num_phys:%d\n", port->id, port->num_phys); | ||
74 | } | ||
75 | |||
76 | #endif /* SAS_DEBUG */ | ||
diff --git a/drivers/scsi/libsas/sas_dump.h b/drivers/scsi/libsas/sas_dump.h new file mode 100644 index 000000000000..47b45d4f5258 --- /dev/null +++ b/drivers/scsi/libsas/sas_dump.h | |||
@@ -0,0 +1,42 @@ | |||
1 | /* | ||
2 | * Serial Attached SCSI (SAS) Dump/Debugging routines header file | ||
3 | * | ||
4 | * Copyright (C) 2005 Adaptec, Inc. All rights reserved. | ||
5 | * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> | ||
6 | * | ||
7 | * This file is licensed under GPLv2. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License as | ||
11 | * published by the Free Software Foundation; either version 2 of the | ||
12 | * License, or (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #include "sas_internal.h" | ||
26 | |||
27 | #ifdef SAS_DEBUG | ||
28 | |||
29 | void sas_dprint_porte(int phyid, enum port_event pe); | ||
30 | void sas_dprint_phye(int phyid, enum phy_event pe); | ||
31 | void sas_dprint_hae(struct sas_ha_struct *sas_ha, enum ha_event he); | ||
32 | void sas_dump_port(struct asd_sas_port *port); | ||
33 | |||
34 | #else /* SAS_DEBUG */ | ||
35 | |||
36 | static inline void sas_dprint_porte(int phyid, enum port_event pe) { } | ||
37 | static inline void sas_dprint_phye(int phyid, enum phy_event pe) { } | ||
38 | static inline void sas_dprint_hae(struct sas_ha_struct *sas_ha, | ||
39 | enum ha_event he) { } | ||
40 | static inline void sas_dump_port(struct asd_sas_port *port) { } | ||
41 | |||
42 | #endif /* SAS_DEBUG */ | ||
diff --git a/drivers/scsi/libsas/sas_event.c b/drivers/scsi/libsas/sas_event.c new file mode 100644 index 000000000000..19110ed1c89c --- /dev/null +++ b/drivers/scsi/libsas/sas_event.c | |||
@@ -0,0 +1,75 @@ | |||
1 | /* | ||
2 | * Serial Attached SCSI (SAS) Event processing | ||
3 | * | ||
4 | * Copyright (C) 2005 Adaptec, Inc. All rights reserved. | ||
5 | * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> | ||
6 | * | ||
7 | * This file is licensed under GPLv2. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License as | ||
11 | * published by the Free Software Foundation; either version 2 of the | ||
12 | * License, or (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #include <scsi/scsi_host.h> | ||
26 | #include "sas_internal.h" | ||
27 | #include "sas_dump.h" | ||
28 | |||
29 | static void notify_ha_event(struct sas_ha_struct *sas_ha, enum ha_event event) | ||
30 | { | ||
31 | BUG_ON(event >= HA_NUM_EVENTS); | ||
32 | |||
33 | sas_queue_event(event, &sas_ha->event_lock, &sas_ha->pending, | ||
34 | &sas_ha->ha_events[event], sas_ha->core.shost); | ||
35 | } | ||
36 | |||
37 | static void notify_port_event(struct asd_sas_phy *phy, enum port_event event) | ||
38 | { | ||
39 | struct sas_ha_struct *ha = phy->ha; | ||
40 | |||
41 | BUG_ON(event >= PORT_NUM_EVENTS); | ||
42 | |||
43 | sas_queue_event(event, &ha->event_lock, &phy->port_events_pending, | ||
44 | &phy->port_events[event], ha->core.shost); | ||
45 | } | ||
46 | |||
47 | static void notify_phy_event(struct asd_sas_phy *phy, enum phy_event event) | ||
48 | { | ||
49 | struct sas_ha_struct *ha = phy->ha; | ||
50 | |||
51 | BUG_ON(event >= PHY_NUM_EVENTS); | ||
52 | |||
53 | sas_queue_event(event, &ha->event_lock, &phy->phy_events_pending, | ||
54 | &phy->phy_events[event], ha->core.shost); | ||
55 | } | ||
56 | |||
57 | int sas_init_events(struct sas_ha_struct *sas_ha) | ||
58 | { | ||
59 | static void (*sas_ha_event_fns[HA_NUM_EVENTS])(void *) = { | ||
60 | [HAE_RESET] = sas_hae_reset, | ||
61 | }; | ||
62 | |||
63 | int i; | ||
64 | |||
65 | spin_lock_init(&sas_ha->event_lock); | ||
66 | |||
67 | for (i = 0; i < HA_NUM_EVENTS; i++) | ||
68 | INIT_WORK(&sas_ha->ha_events[i], sas_ha_event_fns[i], sas_ha); | ||
69 | |||
70 | sas_ha->notify_ha_event = notify_ha_event; | ||
71 | sas_ha->notify_port_event = notify_port_event; | ||
72 | sas_ha->notify_phy_event = notify_phy_event; | ||
73 | |||
74 | return 0; | ||
75 | } | ||
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c new file mode 100644 index 000000000000..b653a263f76a --- /dev/null +++ b/drivers/scsi/libsas/sas_expander.c | |||
@@ -0,0 +1,1862 @@ | |||
1 | /* | ||
2 | * Serial Attached SCSI (SAS) Expander discovery and configuration | ||
3 | * | ||
4 | * Copyright (C) 2005 Adaptec, Inc. All rights reserved. | ||
5 | * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> | ||
6 | * | ||
7 | * This file is licensed under GPLv2. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License as | ||
11 | * published by the Free Software Foundation; either version 2 of the | ||
12 | * License, or (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #include <linux/pci.h> | ||
26 | #include <linux/scatterlist.h> | ||
27 | |||
28 | #include "sas_internal.h" | ||
29 | |||
30 | #include <scsi/scsi_transport.h> | ||
31 | #include <scsi/scsi_transport_sas.h> | ||
32 | #include "../scsi_sas_internal.h" | ||
33 | |||
34 | static int sas_discover_expander(struct domain_device *dev); | ||
35 | static int sas_configure_routing(struct domain_device *dev, u8 *sas_addr); | ||
36 | static int sas_configure_phy(struct domain_device *dev, int phy_id, | ||
37 | u8 *sas_addr, int include); | ||
38 | static int sas_disable_routing(struct domain_device *dev, u8 *sas_addr); | ||
39 | |||
40 | #if 0 | ||
41 | /* FIXME: smp needs to migrate into the sas class */ | ||
42 | static ssize_t smp_portal_read(struct kobject *, char *, loff_t, size_t); | ||
43 | static ssize_t smp_portal_write(struct kobject *, char *, loff_t, size_t); | ||
44 | #endif | ||
45 | |||
46 | /* ---------- SMP task management ---------- */ | ||
47 | |||
48 | static void smp_task_timedout(unsigned long _task) | ||
49 | { | ||
50 | struct sas_task *task = (void *) _task; | ||
51 | unsigned long flags; | ||
52 | |||
53 | spin_lock_irqsave(&task->task_state_lock, flags); | ||
54 | if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) | ||
55 | task->task_state_flags |= SAS_TASK_STATE_ABORTED; | ||
56 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
57 | |||
58 | complete(&task->completion); | ||
59 | } | ||
60 | |||
61 | static void smp_task_done(struct sas_task *task) | ||
62 | { | ||
63 | if (!del_timer(&task->timer)) | ||
64 | return; | ||
65 | complete(&task->completion); | ||
66 | } | ||
67 | |||
68 | /* Give it some long enough timeout. In seconds. */ | ||
69 | #define SMP_TIMEOUT 10 | ||
70 | |||
71 | static int smp_execute_task(struct domain_device *dev, void *req, int req_size, | ||
72 | void *resp, int resp_size) | ||
73 | { | ||
74 | int res; | ||
75 | struct sas_task *task = sas_alloc_task(GFP_KERNEL); | ||
76 | struct sas_internal *i = | ||
77 | to_sas_internal(dev->port->ha->core.shost->transportt); | ||
78 | |||
79 | if (!task) | ||
80 | return -ENOMEM; | ||
81 | |||
82 | task->dev = dev; | ||
83 | task->task_proto = dev->tproto; | ||
84 | sg_init_one(&task->smp_task.smp_req, req, req_size); | ||
85 | sg_init_one(&task->smp_task.smp_resp, resp, resp_size); | ||
86 | |||
87 | task->task_done = smp_task_done; | ||
88 | |||
89 | task->timer.data = (unsigned long) task; | ||
90 | task->timer.function = smp_task_timedout; | ||
91 | task->timer.expires = jiffies + SMP_TIMEOUT*HZ; | ||
92 | add_timer(&task->timer); | ||
93 | |||
94 | res = i->dft->lldd_execute_task(task, 1, GFP_KERNEL); | ||
95 | |||
96 | if (res) { | ||
97 | del_timer(&task->timer); | ||
98 | SAS_DPRINTK("executing SMP task failed:%d\n", res); | ||
99 | goto ex_err; | ||
100 | } | ||
101 | |||
102 | wait_for_completion(&task->completion); | ||
103 | res = -ETASK; | ||
104 | if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) { | ||
105 | SAS_DPRINTK("smp task timed out or aborted\n"); | ||
106 | i->dft->lldd_abort_task(task); | ||
107 | if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { | ||
108 | SAS_DPRINTK("SMP task aborted and not done\n"); | ||
109 | goto ex_err; | ||
110 | } | ||
111 | } | ||
112 | if (task->task_status.resp == SAS_TASK_COMPLETE && | ||
113 | task->task_status.stat == SAM_GOOD) | ||
114 | res = 0; | ||
115 | else | ||
116 | SAS_DPRINTK("%s: task to dev %016llx response: 0x%x " | ||
117 | "status 0x%x\n", __FUNCTION__, | ||
118 | SAS_ADDR(dev->sas_addr), | ||
119 | task->task_status.resp, | ||
120 | task->task_status.stat); | ||
121 | ex_err: | ||
122 | sas_free_task(task); | ||
123 | return res; | ||
124 | } | ||
125 | |||
126 | /* ---------- Allocations ---------- */ | ||
127 | |||
128 | static inline void *alloc_smp_req(int size) | ||
129 | { | ||
130 | u8 *p = kzalloc(size, GFP_KERNEL); | ||
131 | if (p) | ||
132 | p[0] = SMP_REQUEST; | ||
133 | return p; | ||
134 | } | ||
135 | |||
136 | static inline void *alloc_smp_resp(int size) | ||
137 | { | ||
138 | return kzalloc(size, GFP_KERNEL); | ||
139 | } | ||
140 | |||
141 | /* ---------- Expander configuration ---------- */ | ||
142 | |||
143 | static void sas_set_ex_phy(struct domain_device *dev, int phy_id, | ||
144 | void *disc_resp) | ||
145 | { | ||
146 | struct expander_device *ex = &dev->ex_dev; | ||
147 | struct ex_phy *phy = &ex->ex_phy[phy_id]; | ||
148 | struct smp_resp *resp = disc_resp; | ||
149 | struct discover_resp *dr = &resp->disc; | ||
150 | struct sas_rphy *rphy = dev->rphy; | ||
151 | int rediscover = (phy->phy != NULL); | ||
152 | |||
153 | if (!rediscover) { | ||
154 | phy->phy = sas_phy_alloc(&rphy->dev, phy_id); | ||
155 | |||
156 | /* FIXME: error_handling */ | ||
157 | BUG_ON(!phy->phy); | ||
158 | } | ||
159 | |||
160 | switch (resp->result) { | ||
161 | case SMP_RESP_PHY_VACANT: | ||
162 | phy->phy_state = PHY_VACANT; | ||
163 | return; | ||
164 | default: | ||
165 | phy->phy_state = PHY_NOT_PRESENT; | ||
166 | return; | ||
167 | case SMP_RESP_FUNC_ACC: | ||
168 | phy->phy_state = PHY_EMPTY; /* do not know yet */ | ||
169 | break; | ||
170 | } | ||
171 | |||
172 | phy->phy_id = phy_id; | ||
173 | phy->attached_dev_type = dr->attached_dev_type; | ||
174 | phy->linkrate = dr->linkrate; | ||
175 | phy->attached_sata_host = dr->attached_sata_host; | ||
176 | phy->attached_sata_dev = dr->attached_sata_dev; | ||
177 | phy->attached_sata_ps = dr->attached_sata_ps; | ||
178 | phy->attached_iproto = dr->iproto << 1; | ||
179 | phy->attached_tproto = dr->tproto << 1; | ||
180 | memcpy(phy->attached_sas_addr, dr->attached_sas_addr, SAS_ADDR_SIZE); | ||
181 | phy->attached_phy_id = dr->attached_phy_id; | ||
182 | phy->phy_change_count = dr->change_count; | ||
183 | phy->routing_attr = dr->routing_attr; | ||
184 | phy->virtual = dr->virtual; | ||
185 | phy->last_da_index = -1; | ||
186 | |||
187 | phy->phy->identify.initiator_port_protocols = phy->attached_iproto; | ||
188 | phy->phy->identify.target_port_protocols = phy->attached_tproto; | ||
189 | phy->phy->identify.phy_identifier = phy_id; | ||
190 | phy->phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS; | ||
191 | phy->phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS; | ||
192 | phy->phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS; | ||
193 | phy->phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS; | ||
194 | switch (phy->linkrate) { | ||
195 | case PHY_LINKRATE_1_5: | ||
196 | phy->phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS; | ||
197 | break; | ||
198 | case PHY_LINKRATE_3: | ||
199 | phy->phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS; | ||
200 | break; | ||
201 | case PHY_LINKRATE_6: | ||
202 | phy->phy->negotiated_linkrate = SAS_LINK_RATE_6_0_GBPS; | ||
203 | break; | ||
204 | default: | ||
205 | phy->phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN; | ||
206 | break; | ||
207 | } | ||
208 | |||
209 | if (!rediscover) | ||
210 | sas_phy_add(phy->phy); | ||
211 | |||
212 | SAS_DPRINTK("ex %016llx phy%02d:%c attached: %016llx\n", | ||
213 | SAS_ADDR(dev->sas_addr), phy->phy_id, | ||
214 | phy->routing_attr == TABLE_ROUTING ? 'T' : | ||
215 | phy->routing_attr == DIRECT_ROUTING ? 'D' : | ||
216 | phy->routing_attr == SUBTRACTIVE_ROUTING ? 'S' : '?', | ||
217 | SAS_ADDR(phy->attached_sas_addr)); | ||
218 | |||
219 | return; | ||
220 | } | ||
221 | |||
222 | #define DISCOVER_REQ_SIZE 16 | ||
223 | #define DISCOVER_RESP_SIZE 56 | ||
224 | |||
225 | static int sas_ex_phy_discover(struct domain_device *dev, int single) | ||
226 | { | ||
227 | struct expander_device *ex = &dev->ex_dev; | ||
228 | int res = 0; | ||
229 | u8 *disc_req; | ||
230 | u8 *disc_resp; | ||
231 | |||
232 | disc_req = alloc_smp_req(DISCOVER_REQ_SIZE); | ||
233 | if (!disc_req) | ||
234 | return -ENOMEM; | ||
235 | |||
236 | disc_resp = alloc_smp_req(DISCOVER_RESP_SIZE); | ||
237 | if (!disc_resp) { | ||
238 | kfree(disc_req); | ||
239 | return -ENOMEM; | ||
240 | } | ||
241 | |||
242 | disc_req[1] = SMP_DISCOVER; | ||
243 | |||
244 | if (0 <= single && single < ex->num_phys) { | ||
245 | disc_req[9] = single; | ||
246 | res = smp_execute_task(dev, disc_req, DISCOVER_REQ_SIZE, | ||
247 | disc_resp, DISCOVER_RESP_SIZE); | ||
248 | if (res) | ||
249 | goto out_err; | ||
250 | sas_set_ex_phy(dev, single, disc_resp); | ||
251 | } else { | ||
252 | int i; | ||
253 | |||
254 | for (i = 0; i < ex->num_phys; i++) { | ||
255 | disc_req[9] = i; | ||
256 | res = smp_execute_task(dev, disc_req, | ||
257 | DISCOVER_REQ_SIZE, disc_resp, | ||
258 | DISCOVER_RESP_SIZE); | ||
259 | if (res) | ||
260 | goto out_err; | ||
261 | sas_set_ex_phy(dev, i, disc_resp); | ||
262 | } | ||
263 | } | ||
264 | out_err: | ||
265 | kfree(disc_resp); | ||
266 | kfree(disc_req); | ||
267 | return res; | ||
268 | } | ||
269 | |||
270 | static int sas_expander_discover(struct domain_device *dev) | ||
271 | { | ||
272 | struct expander_device *ex = &dev->ex_dev; | ||
273 | int res = -ENOMEM; | ||
274 | |||
275 | ex->ex_phy = kzalloc(sizeof(*ex->ex_phy)*ex->num_phys, GFP_KERNEL); | ||
276 | if (!ex->ex_phy) | ||
277 | return -ENOMEM; | ||
278 | |||
279 | res = sas_ex_phy_discover(dev, -1); | ||
280 | if (res) | ||
281 | goto out_err; | ||
282 | |||
283 | return 0; | ||
284 | out_err: | ||
285 | kfree(ex->ex_phy); | ||
286 | ex->ex_phy = NULL; | ||
287 | return res; | ||
288 | } | ||
289 | |||
290 | #define MAX_EXPANDER_PHYS 128 | ||
291 | |||
292 | static void ex_assign_report_general(struct domain_device *dev, | ||
293 | struct smp_resp *resp) | ||
294 | { | ||
295 | struct report_general_resp *rg = &resp->rg; | ||
296 | |||
297 | dev->ex_dev.ex_change_count = be16_to_cpu(rg->change_count); | ||
298 | dev->ex_dev.max_route_indexes = be16_to_cpu(rg->route_indexes); | ||
299 | dev->ex_dev.num_phys = min(rg->num_phys, (u8)MAX_EXPANDER_PHYS); | ||
300 | dev->ex_dev.conf_route_table = rg->conf_route_table; | ||
301 | dev->ex_dev.configuring = rg->configuring; | ||
302 | memcpy(dev->ex_dev.enclosure_logical_id, rg->enclosure_logical_id, 8); | ||
303 | } | ||
304 | |||
305 | #define RG_REQ_SIZE 8 | ||
306 | #define RG_RESP_SIZE 32 | ||
307 | |||
308 | static int sas_ex_general(struct domain_device *dev) | ||
309 | { | ||
310 | u8 *rg_req; | ||
311 | struct smp_resp *rg_resp; | ||
312 | int res; | ||
313 | int i; | ||
314 | |||
315 | rg_req = alloc_smp_req(RG_REQ_SIZE); | ||
316 | if (!rg_req) | ||
317 | return -ENOMEM; | ||
318 | |||
319 | rg_resp = alloc_smp_resp(RG_RESP_SIZE); | ||
320 | if (!rg_resp) { | ||
321 | kfree(rg_req); | ||
322 | return -ENOMEM; | ||
323 | } | ||
324 | |||
325 | rg_req[1] = SMP_REPORT_GENERAL; | ||
326 | |||
327 | for (i = 0; i < 5; i++) { | ||
328 | res = smp_execute_task(dev, rg_req, RG_REQ_SIZE, rg_resp, | ||
329 | RG_RESP_SIZE); | ||
330 | |||
331 | if (res) { | ||
332 | SAS_DPRINTK("RG to ex %016llx failed:0x%x\n", | ||
333 | SAS_ADDR(dev->sas_addr), res); | ||
334 | goto out; | ||
335 | } else if (rg_resp->result != SMP_RESP_FUNC_ACC) { | ||
336 | SAS_DPRINTK("RG:ex %016llx returned SMP result:0x%x\n", | ||
337 | SAS_ADDR(dev->sas_addr), rg_resp->result); | ||
338 | res = rg_resp->result; | ||
339 | goto out; | ||
340 | } | ||
341 | |||
342 | ex_assign_report_general(dev, rg_resp); | ||
343 | |||
344 | if (dev->ex_dev.configuring) { | ||
345 | SAS_DPRINTK("RG: ex %llx self-configuring...\n", | ||
346 | SAS_ADDR(dev->sas_addr)); | ||
347 | schedule_timeout_interruptible(5*HZ); | ||
348 | } else | ||
349 | break; | ||
350 | } | ||
351 | out: | ||
352 | kfree(rg_req); | ||
353 | kfree(rg_resp); | ||
354 | return res; | ||
355 | } | ||
356 | |||
357 | static void ex_assign_manuf_info(struct domain_device *dev, void | ||
358 | *_mi_resp) | ||
359 | { | ||
360 | u8 *mi_resp = _mi_resp; | ||
361 | struct sas_rphy *rphy = dev->rphy; | ||
362 | struct sas_expander_device *edev = rphy_to_expander_device(rphy); | ||
363 | |||
364 | memcpy(edev->vendor_id, mi_resp + 12, SAS_EXPANDER_VENDOR_ID_LEN); | ||
365 | memcpy(edev->product_id, mi_resp + 20, SAS_EXPANDER_PRODUCT_ID_LEN); | ||
366 | memcpy(edev->product_rev, mi_resp + 36, | ||
367 | SAS_EXPANDER_PRODUCT_REV_LEN); | ||
368 | |||
369 | if (mi_resp[8] & 1) { | ||
370 | memcpy(edev->component_vendor_id, mi_resp + 40, | ||
371 | SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN); | ||
372 | edev->component_id = mi_resp[48] << 8 | mi_resp[49]; | ||
373 | edev->component_revision_id = mi_resp[50]; | ||
374 | } | ||
375 | } | ||
376 | |||
377 | #define MI_REQ_SIZE 8 | ||
378 | #define MI_RESP_SIZE 64 | ||
379 | |||
380 | static int sas_ex_manuf_info(struct domain_device *dev) | ||
381 | { | ||
382 | u8 *mi_req; | ||
383 | u8 *mi_resp; | ||
384 | int res; | ||
385 | |||
386 | mi_req = alloc_smp_req(MI_REQ_SIZE); | ||
387 | if (!mi_req) | ||
388 | return -ENOMEM; | ||
389 | |||
390 | mi_resp = alloc_smp_resp(MI_RESP_SIZE); | ||
391 | if (!mi_resp) { | ||
392 | kfree(mi_req); | ||
393 | return -ENOMEM; | ||
394 | } | ||
395 | |||
396 | mi_req[1] = SMP_REPORT_MANUF_INFO; | ||
397 | |||
398 | res = smp_execute_task(dev, mi_req, MI_REQ_SIZE, mi_resp,MI_RESP_SIZE); | ||
399 | if (res) { | ||
400 | SAS_DPRINTK("MI: ex %016llx failed:0x%x\n", | ||
401 | SAS_ADDR(dev->sas_addr), res); | ||
402 | goto out; | ||
403 | } else if (mi_resp[2] != SMP_RESP_FUNC_ACC) { | ||
404 | SAS_DPRINTK("MI ex %016llx returned SMP result:0x%x\n", | ||
405 | SAS_ADDR(dev->sas_addr), mi_resp[2]); | ||
406 | goto out; | ||
407 | } | ||
408 | |||
409 | ex_assign_manuf_info(dev, mi_resp); | ||
410 | out: | ||
411 | kfree(mi_req); | ||
412 | kfree(mi_resp); | ||
413 | return res; | ||
414 | } | ||
415 | |||
416 | #define PC_REQ_SIZE 44 | ||
417 | #define PC_RESP_SIZE 8 | ||
418 | |||
419 | int sas_smp_phy_control(struct domain_device *dev, int phy_id, | ||
420 | enum phy_func phy_func) | ||
421 | { | ||
422 | u8 *pc_req; | ||
423 | u8 *pc_resp; | ||
424 | int res; | ||
425 | |||
426 | pc_req = alloc_smp_req(PC_REQ_SIZE); | ||
427 | if (!pc_req) | ||
428 | return -ENOMEM; | ||
429 | |||
430 | pc_resp = alloc_smp_resp(PC_RESP_SIZE); | ||
431 | if (!pc_resp) { | ||
432 | kfree(pc_req); | ||
433 | return -ENOMEM; | ||
434 | } | ||
435 | |||
436 | pc_req[1] = SMP_PHY_CONTROL; | ||
437 | pc_req[9] = phy_id; | ||
438 | pc_req[10]= phy_func; | ||
439 | |||
440 | res = smp_execute_task(dev, pc_req, PC_REQ_SIZE, pc_resp,PC_RESP_SIZE); | ||
441 | |||
442 | kfree(pc_resp); | ||
443 | kfree(pc_req); | ||
444 | return res; | ||
445 | } | ||
446 | |||
447 | static void sas_ex_disable_phy(struct domain_device *dev, int phy_id) | ||
448 | { | ||
449 | struct expander_device *ex = &dev->ex_dev; | ||
450 | struct ex_phy *phy = &ex->ex_phy[phy_id]; | ||
451 | |||
452 | sas_smp_phy_control(dev, phy_id, PHY_FUNC_DISABLE); | ||
453 | phy->linkrate = PHY_DISABLED; | ||
454 | } | ||
455 | |||
456 | static void sas_ex_disable_port(struct domain_device *dev, u8 *sas_addr) | ||
457 | { | ||
458 | struct expander_device *ex = &dev->ex_dev; | ||
459 | int i; | ||
460 | |||
461 | for (i = 0; i < ex->num_phys; i++) { | ||
462 | struct ex_phy *phy = &ex->ex_phy[i]; | ||
463 | |||
464 | if (phy->phy_state == PHY_VACANT || | ||
465 | phy->phy_state == PHY_NOT_PRESENT) | ||
466 | continue; | ||
467 | |||
468 | if (SAS_ADDR(phy->attached_sas_addr) == SAS_ADDR(sas_addr)) | ||
469 | sas_ex_disable_phy(dev, i); | ||
470 | } | ||
471 | } | ||
472 | |||
473 | static int sas_dev_present_in_domain(struct asd_sas_port *port, | ||
474 | u8 *sas_addr) | ||
475 | { | ||
476 | struct domain_device *dev; | ||
477 | |||
478 | if (SAS_ADDR(port->sas_addr) == SAS_ADDR(sas_addr)) | ||
479 | return 1; | ||
480 | list_for_each_entry(dev, &port->dev_list, dev_list_node) { | ||
481 | if (SAS_ADDR(dev->sas_addr) == SAS_ADDR(sas_addr)) | ||
482 | return 1; | ||
483 | } | ||
484 | return 0; | ||
485 | } | ||
486 | |||
487 | #define RPEL_REQ_SIZE 16 | ||
488 | #define RPEL_RESP_SIZE 32 | ||
489 | int sas_smp_get_phy_events(struct sas_phy *phy) | ||
490 | { | ||
491 | int res; | ||
492 | struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent); | ||
493 | struct domain_device *dev = sas_find_dev_by_rphy(rphy); | ||
494 | u8 *req = alloc_smp_req(RPEL_REQ_SIZE); | ||
495 | u8 *resp = kzalloc(RPEL_RESP_SIZE, GFP_KERNEL); | ||
496 | |||
497 | if (!resp) | ||
498 | return -ENOMEM; | ||
499 | |||
500 | req[1] = SMP_REPORT_PHY_ERR_LOG; | ||
501 | req[9] = phy->number; | ||
502 | |||
503 | res = smp_execute_task(dev, req, RPEL_REQ_SIZE, | ||
504 | resp, RPEL_RESP_SIZE); | ||
505 | |||
506 | if (!res) | ||
507 | goto out; | ||
508 | |||
509 | phy->invalid_dword_count = scsi_to_u32(&resp[12]); | ||
510 | phy->running_disparity_error_count = scsi_to_u32(&resp[16]); | ||
511 | phy->loss_of_dword_sync_count = scsi_to_u32(&resp[20]); | ||
512 | phy->phy_reset_problem_count = scsi_to_u32(&resp[24]); | ||
513 | |||
514 | out: | ||
515 | kfree(resp); | ||
516 | return res; | ||
517 | |||
518 | } | ||
519 | |||
520 | #define RPS_REQ_SIZE 16 | ||
521 | #define RPS_RESP_SIZE 60 | ||
522 | |||
523 | static int sas_get_report_phy_sata(struct domain_device *dev, | ||
524 | int phy_id, | ||
525 | struct smp_resp *rps_resp) | ||
526 | { | ||
527 | int res; | ||
528 | u8 *rps_req = alloc_smp_req(RPS_REQ_SIZE); | ||
529 | |||
530 | if (!rps_req) | ||
531 | return -ENOMEM; | ||
532 | |||
533 | rps_req[1] = SMP_REPORT_PHY_SATA; | ||
534 | rps_req[9] = phy_id; | ||
535 | |||
536 | res = smp_execute_task(dev, rps_req, RPS_REQ_SIZE, | ||
537 | rps_resp, RPS_RESP_SIZE); | ||
538 | |||
539 | kfree(rps_req); | ||
540 | return 0; | ||
541 | } | ||
542 | |||
543 | static void sas_ex_get_linkrate(struct domain_device *parent, | ||
544 | struct domain_device *child, | ||
545 | struct ex_phy *parent_phy) | ||
546 | { | ||
547 | struct expander_device *parent_ex = &parent->ex_dev; | ||
548 | struct sas_port *port; | ||
549 | int i; | ||
550 | |||
551 | child->pathways = 0; | ||
552 | |||
553 | port = parent_phy->port; | ||
554 | |||
555 | for (i = 0; i < parent_ex->num_phys; i++) { | ||
556 | struct ex_phy *phy = &parent_ex->ex_phy[i]; | ||
557 | |||
558 | if (phy->phy_state == PHY_VACANT || | ||
559 | phy->phy_state == PHY_NOT_PRESENT) | ||
560 | continue; | ||
561 | |||
562 | if (SAS_ADDR(phy->attached_sas_addr) == | ||
563 | SAS_ADDR(child->sas_addr)) { | ||
564 | |||
565 | child->min_linkrate = min(parent->min_linkrate, | ||
566 | phy->linkrate); | ||
567 | child->max_linkrate = max(parent->max_linkrate, | ||
568 | phy->linkrate); | ||
569 | child->pathways++; | ||
570 | sas_port_add_phy(port, phy->phy); | ||
571 | } | ||
572 | } | ||
573 | child->linkrate = min(parent_phy->linkrate, child->max_linkrate); | ||
574 | child->pathways = min(child->pathways, parent->pathways); | ||
575 | } | ||
576 | |||
577 | static struct domain_device *sas_ex_discover_end_dev( | ||
578 | struct domain_device *parent, int phy_id) | ||
579 | { | ||
580 | struct expander_device *parent_ex = &parent->ex_dev; | ||
581 | struct ex_phy *phy = &parent_ex->ex_phy[phy_id]; | ||
582 | struct domain_device *child = NULL; | ||
583 | struct sas_rphy *rphy; | ||
584 | int res; | ||
585 | |||
586 | if (phy->attached_sata_host || phy->attached_sata_ps) | ||
587 | return NULL; | ||
588 | |||
589 | child = kzalloc(sizeof(*child), GFP_KERNEL); | ||
590 | if (!child) | ||
591 | return NULL; | ||
592 | |||
593 | child->parent = parent; | ||
594 | child->port = parent->port; | ||
595 | child->iproto = phy->attached_iproto; | ||
596 | memcpy(child->sas_addr, phy->attached_sas_addr, SAS_ADDR_SIZE); | ||
597 | sas_hash_addr(child->hashed_sas_addr, child->sas_addr); | ||
598 | phy->port = sas_port_alloc(&parent->rphy->dev, phy_id); | ||
599 | BUG_ON(!phy->port); | ||
600 | /* FIXME: better error handling*/ | ||
601 | BUG_ON(sas_port_add(phy->port) != 0); | ||
602 | sas_ex_get_linkrate(parent, child, phy); | ||
603 | |||
604 | if ((phy->attached_tproto & SAS_PROTO_STP) || phy->attached_sata_dev) { | ||
605 | child->dev_type = SATA_DEV; | ||
606 | if (phy->attached_tproto & SAS_PROTO_STP) | ||
607 | child->tproto = phy->attached_tproto; | ||
608 | if (phy->attached_sata_dev) | ||
609 | child->tproto |= SATA_DEV; | ||
610 | res = sas_get_report_phy_sata(parent, phy_id, | ||
611 | &child->sata_dev.rps_resp); | ||
612 | if (res) { | ||
613 | SAS_DPRINTK("report phy sata to %016llx:0x%x returned " | ||
614 | "0x%x\n", SAS_ADDR(parent->sas_addr), | ||
615 | phy_id, res); | ||
616 | kfree(child); | ||
617 | return NULL; | ||
618 | } | ||
619 | memcpy(child->frame_rcvd, &child->sata_dev.rps_resp.rps.fis, | ||
620 | sizeof(struct dev_to_host_fis)); | ||
621 | sas_init_dev(child); | ||
622 | res = sas_discover_sata(child); | ||
623 | if (res) { | ||
624 | SAS_DPRINTK("sas_discover_sata() for device %16llx at " | ||
625 | "%016llx:0x%x returned 0x%x\n", | ||
626 | SAS_ADDR(child->sas_addr), | ||
627 | SAS_ADDR(parent->sas_addr), phy_id, res); | ||
628 | kfree(child); | ||
629 | return NULL; | ||
630 | } | ||
631 | } else if (phy->attached_tproto & SAS_PROTO_SSP) { | ||
632 | child->dev_type = SAS_END_DEV; | ||
633 | rphy = sas_end_device_alloc(phy->port); | ||
634 | /* FIXME: error handling */ | ||
635 | BUG_ON(!rphy); | ||
636 | child->tproto = phy->attached_tproto; | ||
637 | sas_init_dev(child); | ||
638 | |||
639 | child->rphy = rphy; | ||
640 | sas_fill_in_rphy(child, rphy); | ||
641 | |||
642 | spin_lock(&parent->port->dev_list_lock); | ||
643 | list_add_tail(&child->dev_list_node, &parent->port->dev_list); | ||
644 | spin_unlock(&parent->port->dev_list_lock); | ||
645 | |||
646 | res = sas_discover_end_dev(child); | ||
647 | if (res) { | ||
648 | SAS_DPRINTK("sas_discover_end_dev() for device %16llx " | ||
649 | "at %016llx:0x%x returned 0x%x\n", | ||
650 | SAS_ADDR(child->sas_addr), | ||
651 | SAS_ADDR(parent->sas_addr), phy_id, res); | ||
652 | /* FIXME: this kfrees list elements without removing them */ | ||
653 | //kfree(child); | ||
654 | return NULL; | ||
655 | } | ||
656 | } else { | ||
657 | SAS_DPRINTK("target proto 0x%x at %016llx:0x%x not handled\n", | ||
658 | phy->attached_tproto, SAS_ADDR(parent->sas_addr), | ||
659 | phy_id); | ||
660 | } | ||
661 | |||
662 | list_add_tail(&child->siblings, &parent_ex->children); | ||
663 | return child; | ||
664 | } | ||
665 | |||
666 | static struct domain_device *sas_ex_discover_expander( | ||
667 | struct domain_device *parent, int phy_id) | ||
668 | { | ||
669 | struct sas_expander_device *parent_ex = rphy_to_expander_device(parent->rphy); | ||
670 | struct ex_phy *phy = &parent->ex_dev.ex_phy[phy_id]; | ||
671 | struct domain_device *child = NULL; | ||
672 | struct sas_rphy *rphy; | ||
673 | struct sas_expander_device *edev; | ||
674 | struct asd_sas_port *port; | ||
675 | int res; | ||
676 | |||
677 | if (phy->routing_attr == DIRECT_ROUTING) { | ||
678 | SAS_DPRINTK("ex %016llx:0x%x:D <--> ex %016llx:0x%x is not " | ||
679 | "allowed\n", | ||
680 | SAS_ADDR(parent->sas_addr), phy_id, | ||
681 | SAS_ADDR(phy->attached_sas_addr), | ||
682 | phy->attached_phy_id); | ||
683 | return NULL; | ||
684 | } | ||
685 | child = kzalloc(sizeof(*child), GFP_KERNEL); | ||
686 | if (!child) | ||
687 | return NULL; | ||
688 | |||
689 | phy->port = sas_port_alloc(&parent->rphy->dev, phy_id); | ||
690 | /* FIXME: better error handling */ | ||
691 | BUG_ON(sas_port_add(phy->port) != 0); | ||
692 | |||
693 | |||
694 | switch (phy->attached_dev_type) { | ||
695 | case EDGE_DEV: | ||
696 | rphy = sas_expander_alloc(phy->port, | ||
697 | SAS_EDGE_EXPANDER_DEVICE); | ||
698 | break; | ||
699 | case FANOUT_DEV: | ||
700 | rphy = sas_expander_alloc(phy->port, | ||
701 | SAS_FANOUT_EXPANDER_DEVICE); | ||
702 | break; | ||
703 | default: | ||
704 | rphy = NULL; /* shut gcc up */ | ||
705 | BUG(); | ||
706 | } | ||
707 | port = parent->port; | ||
708 | child->rphy = rphy; | ||
709 | edev = rphy_to_expander_device(rphy); | ||
710 | child->dev_type = phy->attached_dev_type; | ||
711 | child->parent = parent; | ||
712 | child->port = port; | ||
713 | child->iproto = phy->attached_iproto; | ||
714 | child->tproto = phy->attached_tproto; | ||
715 | memcpy(child->sas_addr, phy->attached_sas_addr, SAS_ADDR_SIZE); | ||
716 | sas_hash_addr(child->hashed_sas_addr, child->sas_addr); | ||
717 | sas_ex_get_linkrate(parent, child, phy); | ||
718 | edev->level = parent_ex->level + 1; | ||
719 | parent->port->disc.max_level = max(parent->port->disc.max_level, | ||
720 | edev->level); | ||
721 | sas_init_dev(child); | ||
722 | sas_fill_in_rphy(child, rphy); | ||
723 | sas_rphy_add(rphy); | ||
724 | |||
725 | spin_lock(&parent->port->dev_list_lock); | ||
726 | list_add_tail(&child->dev_list_node, &parent->port->dev_list); | ||
727 | spin_unlock(&parent->port->dev_list_lock); | ||
728 | |||
729 | res = sas_discover_expander(child); | ||
730 | if (res) { | ||
731 | kfree(child); | ||
732 | return NULL; | ||
733 | } | ||
734 | list_add_tail(&child->siblings, &parent->ex_dev.children); | ||
735 | return child; | ||
736 | } | ||
737 | |||
738 | static int sas_ex_discover_dev(struct domain_device *dev, int phy_id) | ||
739 | { | ||
740 | struct expander_device *ex = &dev->ex_dev; | ||
741 | struct ex_phy *ex_phy = &ex->ex_phy[phy_id]; | ||
742 | struct domain_device *child = NULL; | ||
743 | int res = 0; | ||
744 | |||
745 | /* Phy state */ | ||
746 | if (ex_phy->linkrate == PHY_SPINUP_HOLD) { | ||
747 | if (!sas_smp_phy_control(dev, phy_id, PHY_FUNC_LINK_RESET)) | ||
748 | res = sas_ex_phy_discover(dev, phy_id); | ||
749 | if (res) | ||
750 | return res; | ||
751 | } | ||
752 | |||
753 | /* Parent and domain coherency */ | ||
754 | if (!dev->parent && (SAS_ADDR(ex_phy->attached_sas_addr) == | ||
755 | SAS_ADDR(dev->port->sas_addr))) { | ||
756 | sas_add_parent_port(dev, phy_id); | ||
757 | return 0; | ||
758 | } | ||
759 | if (dev->parent && (SAS_ADDR(ex_phy->attached_sas_addr) == | ||
760 | SAS_ADDR(dev->parent->sas_addr))) { | ||
761 | sas_add_parent_port(dev, phy_id); | ||
762 | if (ex_phy->routing_attr == TABLE_ROUTING) | ||
763 | sas_configure_phy(dev, phy_id, dev->port->sas_addr, 1); | ||
764 | return 0; | ||
765 | } | ||
766 | |||
767 | if (sas_dev_present_in_domain(dev->port, ex_phy->attached_sas_addr)) | ||
768 | sas_ex_disable_port(dev, ex_phy->attached_sas_addr); | ||
769 | |||
770 | if (ex_phy->attached_dev_type == NO_DEVICE) { | ||
771 | if (ex_phy->routing_attr == DIRECT_ROUTING) { | ||
772 | memset(ex_phy->attached_sas_addr, 0, SAS_ADDR_SIZE); | ||
773 | sas_configure_routing(dev, ex_phy->attached_sas_addr); | ||
774 | } | ||
775 | return 0; | ||
776 | } else if (ex_phy->linkrate == PHY_LINKRATE_UNKNOWN) | ||
777 | return 0; | ||
778 | |||
779 | if (ex_phy->attached_dev_type != SAS_END_DEV && | ||
780 | ex_phy->attached_dev_type != FANOUT_DEV && | ||
781 | ex_phy->attached_dev_type != EDGE_DEV) { | ||
782 | SAS_DPRINTK("unknown device type(0x%x) attached to ex %016llx " | ||
783 | "phy 0x%x\n", ex_phy->attached_dev_type, | ||
784 | SAS_ADDR(dev->sas_addr), | ||
785 | phy_id); | ||
786 | return 0; | ||
787 | } | ||
788 | |||
789 | res = sas_configure_routing(dev, ex_phy->attached_sas_addr); | ||
790 | if (res) { | ||
791 | SAS_DPRINTK("configure routing for dev %016llx " | ||
792 | "reported 0x%x. Forgotten\n", | ||
793 | SAS_ADDR(ex_phy->attached_sas_addr), res); | ||
794 | sas_disable_routing(dev, ex_phy->attached_sas_addr); | ||
795 | return res; | ||
796 | } | ||
797 | |||
798 | switch (ex_phy->attached_dev_type) { | ||
799 | case SAS_END_DEV: | ||
800 | child = sas_ex_discover_end_dev(dev, phy_id); | ||
801 | break; | ||
802 | case FANOUT_DEV: | ||
803 | if (SAS_ADDR(dev->port->disc.fanout_sas_addr)) { | ||
804 | SAS_DPRINTK("second fanout expander %016llx phy 0x%x " | ||
805 | "attached to ex %016llx phy 0x%x\n", | ||
806 | SAS_ADDR(ex_phy->attached_sas_addr), | ||
807 | ex_phy->attached_phy_id, | ||
808 | SAS_ADDR(dev->sas_addr), | ||
809 | phy_id); | ||
810 | sas_ex_disable_phy(dev, phy_id); | ||
811 | break; | ||
812 | } else | ||
813 | memcpy(dev->port->disc.fanout_sas_addr, | ||
814 | ex_phy->attached_sas_addr, SAS_ADDR_SIZE); | ||
815 | /* fallthrough */ | ||
816 | case EDGE_DEV: | ||
817 | child = sas_ex_discover_expander(dev, phy_id); | ||
818 | break; | ||
819 | default: | ||
820 | break; | ||
821 | } | ||
822 | |||
823 | if (child) { | ||
824 | int i; | ||
825 | |||
826 | for (i = 0; i < ex->num_phys; i++) { | ||
827 | if (ex->ex_phy[i].phy_state == PHY_VACANT || | ||
828 | ex->ex_phy[i].phy_state == PHY_NOT_PRESENT) | ||
829 | continue; | ||
830 | |||
831 | if (SAS_ADDR(ex->ex_phy[i].attached_sas_addr) == | ||
832 | SAS_ADDR(child->sas_addr)) | ||
833 | ex->ex_phy[i].phy_state= PHY_DEVICE_DISCOVERED; | ||
834 | } | ||
835 | } | ||
836 | |||
837 | return res; | ||
838 | } | ||
839 | |||
840 | static int sas_find_sub_addr(struct domain_device *dev, u8 *sub_addr) | ||
841 | { | ||
842 | struct expander_device *ex = &dev->ex_dev; | ||
843 | int i; | ||
844 | |||
845 | for (i = 0; i < ex->num_phys; i++) { | ||
846 | struct ex_phy *phy = &ex->ex_phy[i]; | ||
847 | |||
848 | if (phy->phy_state == PHY_VACANT || | ||
849 | phy->phy_state == PHY_NOT_PRESENT) | ||
850 | continue; | ||
851 | |||
852 | if ((phy->attached_dev_type == EDGE_DEV || | ||
853 | phy->attached_dev_type == FANOUT_DEV) && | ||
854 | phy->routing_attr == SUBTRACTIVE_ROUTING) { | ||
855 | |||
856 | memcpy(sub_addr, phy->attached_sas_addr,SAS_ADDR_SIZE); | ||
857 | |||
858 | return 1; | ||
859 | } | ||
860 | } | ||
861 | return 0; | ||
862 | } | ||
863 | |||
864 | static int sas_check_level_subtractive_boundary(struct domain_device *dev) | ||
865 | { | ||
866 | struct expander_device *ex = &dev->ex_dev; | ||
867 | struct domain_device *child; | ||
868 | u8 sub_addr[8] = {0, }; | ||
869 | |||
870 | list_for_each_entry(child, &ex->children, siblings) { | ||
871 | if (child->dev_type != EDGE_DEV && | ||
872 | child->dev_type != FANOUT_DEV) | ||
873 | continue; | ||
874 | if (sub_addr[0] == 0) { | ||
875 | sas_find_sub_addr(child, sub_addr); | ||
876 | continue; | ||
877 | } else { | ||
878 | u8 s2[8]; | ||
879 | |||
880 | if (sas_find_sub_addr(child, s2) && | ||
881 | (SAS_ADDR(sub_addr) != SAS_ADDR(s2))) { | ||
882 | |||
883 | SAS_DPRINTK("ex %016llx->%016llx-?->%016llx " | ||
884 | "diverges from subtractive " | ||
885 | "boundary %016llx\n", | ||
886 | SAS_ADDR(dev->sas_addr), | ||
887 | SAS_ADDR(child->sas_addr), | ||
888 | SAS_ADDR(s2), | ||
889 | SAS_ADDR(sub_addr)); | ||
890 | |||
891 | sas_ex_disable_port(child, s2); | ||
892 | } | ||
893 | } | ||
894 | } | ||
895 | return 0; | ||
896 | } | ||
897 | /** | ||
898 | * sas_ex_discover_devices -- discover devices attached to this expander | ||
899 | * dev: pointer to the expander domain device | ||
900 | * single: if you want to do a single phy, else set to -1; | ||
901 | * | ||
902 | * Configure this expander for use with its devices and register the | ||
903 | * devices of this expander. | ||
904 | */ | ||
905 | static int sas_ex_discover_devices(struct domain_device *dev, int single) | ||
906 | { | ||
907 | struct expander_device *ex = &dev->ex_dev; | ||
908 | int i = 0, end = ex->num_phys; | ||
909 | int res = 0; | ||
910 | |||
911 | if (0 <= single && single < end) { | ||
912 | i = single; | ||
913 | end = i+1; | ||
914 | } | ||
915 | |||
916 | for ( ; i < end; i++) { | ||
917 | struct ex_phy *ex_phy = &ex->ex_phy[i]; | ||
918 | |||
919 | if (ex_phy->phy_state == PHY_VACANT || | ||
920 | ex_phy->phy_state == PHY_NOT_PRESENT || | ||
921 | ex_phy->phy_state == PHY_DEVICE_DISCOVERED) | ||
922 | continue; | ||
923 | |||
924 | switch (ex_phy->linkrate) { | ||
925 | case PHY_DISABLED: | ||
926 | case PHY_RESET_PROBLEM: | ||
927 | case PHY_PORT_SELECTOR: | ||
928 | continue; | ||
929 | default: | ||
930 | res = sas_ex_discover_dev(dev, i); | ||
931 | if (res) | ||
932 | break; | ||
933 | continue; | ||
934 | } | ||
935 | } | ||
936 | |||
937 | if (!res) | ||
938 | sas_check_level_subtractive_boundary(dev); | ||
939 | |||
940 | return res; | ||
941 | } | ||
942 | |||
943 | static int sas_check_ex_subtractive_boundary(struct domain_device *dev) | ||
944 | { | ||
945 | struct expander_device *ex = &dev->ex_dev; | ||
946 | int i; | ||
947 | u8 *sub_sas_addr = NULL; | ||
948 | |||
949 | if (dev->dev_type != EDGE_DEV) | ||
950 | return 0; | ||
951 | |||
952 | for (i = 0; i < ex->num_phys; i++) { | ||
953 | struct ex_phy *phy = &ex->ex_phy[i]; | ||
954 | |||
955 | if (phy->phy_state == PHY_VACANT || | ||
956 | phy->phy_state == PHY_NOT_PRESENT) | ||
957 | continue; | ||
958 | |||
959 | if ((phy->attached_dev_type == FANOUT_DEV || | ||
960 | phy->attached_dev_type == EDGE_DEV) && | ||
961 | phy->routing_attr == SUBTRACTIVE_ROUTING) { | ||
962 | |||
963 | if (!sub_sas_addr) | ||
964 | sub_sas_addr = &phy->attached_sas_addr[0]; | ||
965 | else if (SAS_ADDR(sub_sas_addr) != | ||
966 | SAS_ADDR(phy->attached_sas_addr)) { | ||
967 | |||
968 | SAS_DPRINTK("ex %016llx phy 0x%x " | ||
969 | "diverges(%016llx) on subtractive " | ||
970 | "boundary(%016llx). Disabled\n", | ||
971 | SAS_ADDR(dev->sas_addr), i, | ||
972 | SAS_ADDR(phy->attached_sas_addr), | ||
973 | SAS_ADDR(sub_sas_addr)); | ||
974 | sas_ex_disable_phy(dev, i); | ||
975 | } | ||
976 | } | ||
977 | } | ||
978 | return 0; | ||
979 | } | ||
980 | |||
981 | static void sas_print_parent_topology_bug(struct domain_device *child, | ||
982 | struct ex_phy *parent_phy, | ||
983 | struct ex_phy *child_phy) | ||
984 | { | ||
985 | static const char ra_char[] = { | ||
986 | [DIRECT_ROUTING] = 'D', | ||
987 | [SUBTRACTIVE_ROUTING] = 'S', | ||
988 | [TABLE_ROUTING] = 'T', | ||
989 | }; | ||
990 | static const char *ex_type[] = { | ||
991 | [EDGE_DEV] = "edge", | ||
992 | [FANOUT_DEV] = "fanout", | ||
993 | }; | ||
994 | struct domain_device *parent = child->parent; | ||
995 | |||
996 | sas_printk("%s ex %016llx phy 0x%x <--> %s ex %016llx phy 0x%x " | ||
997 | "has %c:%c routing link!\n", | ||
998 | |||
999 | ex_type[parent->dev_type], | ||
1000 | SAS_ADDR(parent->sas_addr), | ||
1001 | parent_phy->phy_id, | ||
1002 | |||
1003 | ex_type[child->dev_type], | ||
1004 | SAS_ADDR(child->sas_addr), | ||
1005 | child_phy->phy_id, | ||
1006 | |||
1007 | ra_char[parent_phy->routing_attr], | ||
1008 | ra_char[child_phy->routing_attr]); | ||
1009 | } | ||
1010 | |||
1011 | static int sas_check_eeds(struct domain_device *child, | ||
1012 | struct ex_phy *parent_phy, | ||
1013 | struct ex_phy *child_phy) | ||
1014 | { | ||
1015 | int res = 0; | ||
1016 | struct domain_device *parent = child->parent; | ||
1017 | |||
1018 | if (SAS_ADDR(parent->port->disc.fanout_sas_addr) != 0) { | ||
1019 | res = -ENODEV; | ||
1020 | SAS_DPRINTK("edge ex %016llx phy S:0x%x <--> edge ex %016llx " | ||
1021 | "phy S:0x%x, while there is a fanout ex %016llx\n", | ||
1022 | SAS_ADDR(parent->sas_addr), | ||
1023 | parent_phy->phy_id, | ||
1024 | SAS_ADDR(child->sas_addr), | ||
1025 | child_phy->phy_id, | ||
1026 | SAS_ADDR(parent->port->disc.fanout_sas_addr)); | ||
1027 | } else if (SAS_ADDR(parent->port->disc.eeds_a) == 0) { | ||
1028 | memcpy(parent->port->disc.eeds_a, parent->sas_addr, | ||
1029 | SAS_ADDR_SIZE); | ||
1030 | memcpy(parent->port->disc.eeds_b, child->sas_addr, | ||
1031 | SAS_ADDR_SIZE); | ||
1032 | } else if (((SAS_ADDR(parent->port->disc.eeds_a) == | ||
1033 | SAS_ADDR(parent->sas_addr)) || | ||
1034 | (SAS_ADDR(parent->port->disc.eeds_a) == | ||
1035 | SAS_ADDR(child->sas_addr))) | ||
1036 | && | ||
1037 | ((SAS_ADDR(parent->port->disc.eeds_b) == | ||
1038 | SAS_ADDR(parent->sas_addr)) || | ||
1039 | (SAS_ADDR(parent->port->disc.eeds_b) == | ||
1040 | SAS_ADDR(child->sas_addr)))) | ||
1041 | ; | ||
1042 | else { | ||
1043 | res = -ENODEV; | ||
1044 | SAS_DPRINTK("edge ex %016llx phy 0x%x <--> edge ex %016llx " | ||
1045 | "phy 0x%x link forms a third EEDS!\n", | ||
1046 | SAS_ADDR(parent->sas_addr), | ||
1047 | parent_phy->phy_id, | ||
1048 | SAS_ADDR(child->sas_addr), | ||
1049 | child_phy->phy_id); | ||
1050 | } | ||
1051 | |||
1052 | return res; | ||
1053 | } | ||
1054 | |||
1055 | /* Here we spill over 80 columns. It is intentional. | ||
1056 | */ | ||
1057 | static int sas_check_parent_topology(struct domain_device *child) | ||
1058 | { | ||
1059 | struct expander_device *child_ex = &child->ex_dev; | ||
1060 | struct expander_device *parent_ex; | ||
1061 | int i; | ||
1062 | int res = 0; | ||
1063 | |||
1064 | if (!child->parent) | ||
1065 | return 0; | ||
1066 | |||
1067 | if (child->parent->dev_type != EDGE_DEV && | ||
1068 | child->parent->dev_type != FANOUT_DEV) | ||
1069 | return 0; | ||
1070 | |||
1071 | parent_ex = &child->parent->ex_dev; | ||
1072 | |||
1073 | for (i = 0; i < parent_ex->num_phys; i++) { | ||
1074 | struct ex_phy *parent_phy = &parent_ex->ex_phy[i]; | ||
1075 | struct ex_phy *child_phy; | ||
1076 | |||
1077 | if (parent_phy->phy_state == PHY_VACANT || | ||
1078 | parent_phy->phy_state == PHY_NOT_PRESENT) | ||
1079 | continue; | ||
1080 | |||
1081 | if (SAS_ADDR(parent_phy->attached_sas_addr) != SAS_ADDR(child->sas_addr)) | ||
1082 | continue; | ||
1083 | |||
1084 | child_phy = &child_ex->ex_phy[parent_phy->attached_phy_id]; | ||
1085 | |||
1086 | switch (child->parent->dev_type) { | ||
1087 | case EDGE_DEV: | ||
1088 | if (child->dev_type == FANOUT_DEV) { | ||
1089 | if (parent_phy->routing_attr != SUBTRACTIVE_ROUTING || | ||
1090 | child_phy->routing_attr != TABLE_ROUTING) { | ||
1091 | sas_print_parent_topology_bug(child, parent_phy, child_phy); | ||
1092 | res = -ENODEV; | ||
1093 | } | ||
1094 | } else if (parent_phy->routing_attr == SUBTRACTIVE_ROUTING) { | ||
1095 | if (child_phy->routing_attr == SUBTRACTIVE_ROUTING) { | ||
1096 | res = sas_check_eeds(child, parent_phy, child_phy); | ||
1097 | } else if (child_phy->routing_attr != TABLE_ROUTING) { | ||
1098 | sas_print_parent_topology_bug(child, parent_phy, child_phy); | ||
1099 | res = -ENODEV; | ||
1100 | } | ||
1101 | } else if (parent_phy->routing_attr == TABLE_ROUTING && | ||
1102 | child_phy->routing_attr != SUBTRACTIVE_ROUTING) { | ||
1103 | sas_print_parent_topology_bug(child, parent_phy, child_phy); | ||
1104 | res = -ENODEV; | ||
1105 | } | ||
1106 | break; | ||
1107 | case FANOUT_DEV: | ||
1108 | if (parent_phy->routing_attr != TABLE_ROUTING || | ||
1109 | child_phy->routing_attr != SUBTRACTIVE_ROUTING) { | ||
1110 | sas_print_parent_topology_bug(child, parent_phy, child_phy); | ||
1111 | res = -ENODEV; | ||
1112 | } | ||
1113 | break; | ||
1114 | default: | ||
1115 | break; | ||
1116 | } | ||
1117 | } | ||
1118 | |||
1119 | return res; | ||
1120 | } | ||
1121 | |||
1122 | #define RRI_REQ_SIZE 16 | ||
1123 | #define RRI_RESP_SIZE 44 | ||
1124 | |||
1125 | static int sas_configure_present(struct domain_device *dev, int phy_id, | ||
1126 | u8 *sas_addr, int *index, int *present) | ||
1127 | { | ||
1128 | int i, res = 0; | ||
1129 | struct expander_device *ex = &dev->ex_dev; | ||
1130 | struct ex_phy *phy = &ex->ex_phy[phy_id]; | ||
1131 | u8 *rri_req; | ||
1132 | u8 *rri_resp; | ||
1133 | |||
1134 | *present = 0; | ||
1135 | *index = 0; | ||
1136 | |||
1137 | rri_req = alloc_smp_req(RRI_REQ_SIZE); | ||
1138 | if (!rri_req) | ||
1139 | return -ENOMEM; | ||
1140 | |||
1141 | rri_resp = alloc_smp_resp(RRI_RESP_SIZE); | ||
1142 | if (!rri_resp) { | ||
1143 | kfree(rri_req); | ||
1144 | return -ENOMEM; | ||
1145 | } | ||
1146 | |||
1147 | rri_req[1] = SMP_REPORT_ROUTE_INFO; | ||
1148 | rri_req[9] = phy_id; | ||
1149 | |||
1150 | for (i = 0; i < ex->max_route_indexes ; i++) { | ||
1151 | *(__be16 *)(rri_req+6) = cpu_to_be16(i); | ||
1152 | res = smp_execute_task(dev, rri_req, RRI_REQ_SIZE, rri_resp, | ||
1153 | RRI_RESP_SIZE); | ||
1154 | if (res) | ||
1155 | goto out; | ||
1156 | res = rri_resp[2]; | ||
1157 | if (res == SMP_RESP_NO_INDEX) { | ||
1158 | SAS_DPRINTK("overflow of indexes: dev %016llx " | ||
1159 | "phy 0x%x index 0x%x\n", | ||
1160 | SAS_ADDR(dev->sas_addr), phy_id, i); | ||
1161 | goto out; | ||
1162 | } else if (res != SMP_RESP_FUNC_ACC) { | ||
1163 | SAS_DPRINTK("%s: dev %016llx phy 0x%x index 0x%x " | ||
1164 | "result 0x%x\n", __FUNCTION__, | ||
1165 | SAS_ADDR(dev->sas_addr), phy_id, i, res); | ||
1166 | goto out; | ||
1167 | } | ||
1168 | if (SAS_ADDR(sas_addr) != 0) { | ||
1169 | if (SAS_ADDR(rri_resp+16) == SAS_ADDR(sas_addr)) { | ||
1170 | *index = i; | ||
1171 | if ((rri_resp[12] & 0x80) == 0x80) | ||
1172 | *present = 0; | ||
1173 | else | ||
1174 | *present = 1; | ||
1175 | goto out; | ||
1176 | } else if (SAS_ADDR(rri_resp+16) == 0) { | ||
1177 | *index = i; | ||
1178 | *present = 0; | ||
1179 | goto out; | ||
1180 | } | ||
1181 | } else if (SAS_ADDR(rri_resp+16) == 0 && | ||
1182 | phy->last_da_index < i) { | ||
1183 | phy->last_da_index = i; | ||
1184 | *index = i; | ||
1185 | *present = 0; | ||
1186 | goto out; | ||
1187 | } | ||
1188 | } | ||
1189 | res = -1; | ||
1190 | out: | ||
1191 | kfree(rri_req); | ||
1192 | kfree(rri_resp); | ||
1193 | return res; | ||
1194 | } | ||
1195 | |||
1196 | #define CRI_REQ_SIZE 44 | ||
1197 | #define CRI_RESP_SIZE 8 | ||
1198 | |||
1199 | static int sas_configure_set(struct domain_device *dev, int phy_id, | ||
1200 | u8 *sas_addr, int index, int include) | ||
1201 | { | ||
1202 | int res; | ||
1203 | u8 *cri_req; | ||
1204 | u8 *cri_resp; | ||
1205 | |||
1206 | cri_req = alloc_smp_req(CRI_REQ_SIZE); | ||
1207 | if (!cri_req) | ||
1208 | return -ENOMEM; | ||
1209 | |||
1210 | cri_resp = alloc_smp_resp(CRI_RESP_SIZE); | ||
1211 | if (!cri_resp) { | ||
1212 | kfree(cri_req); | ||
1213 | return -ENOMEM; | ||
1214 | } | ||
1215 | |||
1216 | cri_req[1] = SMP_CONF_ROUTE_INFO; | ||
1217 | *(__be16 *)(cri_req+6) = cpu_to_be16(index); | ||
1218 | cri_req[9] = phy_id; | ||
1219 | if (SAS_ADDR(sas_addr) == 0 || !include) | ||
1220 | cri_req[12] |= 0x80; | ||
1221 | memcpy(cri_req+16, sas_addr, SAS_ADDR_SIZE); | ||
1222 | |||
1223 | res = smp_execute_task(dev, cri_req, CRI_REQ_SIZE, cri_resp, | ||
1224 | CRI_RESP_SIZE); | ||
1225 | if (res) | ||
1226 | goto out; | ||
1227 | res = cri_resp[2]; | ||
1228 | if (res == SMP_RESP_NO_INDEX) { | ||
1229 | SAS_DPRINTK("overflow of indexes: dev %016llx phy 0x%x " | ||
1230 | "index 0x%x\n", | ||
1231 | SAS_ADDR(dev->sas_addr), phy_id, index); | ||
1232 | } | ||
1233 | out: | ||
1234 | kfree(cri_req); | ||
1235 | kfree(cri_resp); | ||
1236 | return res; | ||
1237 | } | ||
1238 | |||
1239 | static int sas_configure_phy(struct domain_device *dev, int phy_id, | ||
1240 | u8 *sas_addr, int include) | ||
1241 | { | ||
1242 | int index; | ||
1243 | int present; | ||
1244 | int res; | ||
1245 | |||
1246 | res = sas_configure_present(dev, phy_id, sas_addr, &index, &present); | ||
1247 | if (res) | ||
1248 | return res; | ||
1249 | if (include ^ present) | ||
1250 | return sas_configure_set(dev, phy_id, sas_addr, index,include); | ||
1251 | |||
1252 | return res; | ||
1253 | } | ||
1254 | |||
1255 | /** | ||
1256 | * sas_configure_parent -- configure routing table of parent | ||
1257 | * parent: parent expander | ||
1258 | * child: child expander | ||
1259 | * sas_addr: SAS port identifier of device directly attached to child | ||
1260 | */ | ||
1261 | static int sas_configure_parent(struct domain_device *parent, | ||
1262 | struct domain_device *child, | ||
1263 | u8 *sas_addr, int include) | ||
1264 | { | ||
1265 | struct expander_device *ex_parent = &parent->ex_dev; | ||
1266 | int res = 0; | ||
1267 | int i; | ||
1268 | |||
1269 | if (parent->parent) { | ||
1270 | res = sas_configure_parent(parent->parent, parent, sas_addr, | ||
1271 | include); | ||
1272 | if (res) | ||
1273 | return res; | ||
1274 | } | ||
1275 | |||
1276 | if (ex_parent->conf_route_table == 0) { | ||
1277 | SAS_DPRINTK("ex %016llx has self-configuring routing table\n", | ||
1278 | SAS_ADDR(parent->sas_addr)); | ||
1279 | return 0; | ||
1280 | } | ||
1281 | |||
1282 | for (i = 0; i < ex_parent->num_phys; i++) { | ||
1283 | struct ex_phy *phy = &ex_parent->ex_phy[i]; | ||
1284 | |||
1285 | if ((phy->routing_attr == TABLE_ROUTING) && | ||
1286 | (SAS_ADDR(phy->attached_sas_addr) == | ||
1287 | SAS_ADDR(child->sas_addr))) { | ||
1288 | res = sas_configure_phy(parent, i, sas_addr, include); | ||
1289 | if (res) | ||
1290 | return res; | ||
1291 | } | ||
1292 | } | ||
1293 | |||
1294 | return res; | ||
1295 | } | ||
1296 | |||
1297 | /** | ||
1298 | * sas_configure_routing -- configure routing | ||
1299 | * dev: expander device | ||
1300 | * sas_addr: port identifier of device directly attached to the expander device | ||
1301 | */ | ||
1302 | static int sas_configure_routing(struct domain_device *dev, u8 *sas_addr) | ||
1303 | { | ||
1304 | if (dev->parent) | ||
1305 | return sas_configure_parent(dev->parent, dev, sas_addr, 1); | ||
1306 | return 0; | ||
1307 | } | ||
1308 | |||
1309 | static int sas_disable_routing(struct domain_device *dev, u8 *sas_addr) | ||
1310 | { | ||
1311 | if (dev->parent) | ||
1312 | return sas_configure_parent(dev->parent, dev, sas_addr, 0); | ||
1313 | return 0; | ||
1314 | } | ||
1315 | |||
1316 | #if 0 | ||
1317 | #define SMP_BIN_ATTR_NAME "smp_portal" | ||
1318 | |||
1319 | static void sas_ex_smp_hook(struct domain_device *dev) | ||
1320 | { | ||
1321 | struct expander_device *ex_dev = &dev->ex_dev; | ||
1322 | struct bin_attribute *bin_attr = &ex_dev->smp_bin_attr; | ||
1323 | |||
1324 | memset(bin_attr, 0, sizeof(*bin_attr)); | ||
1325 | |||
1326 | bin_attr->attr.name = SMP_BIN_ATTR_NAME; | ||
1327 | bin_attr->attr.owner = THIS_MODULE; | ||
1328 | bin_attr->attr.mode = 0600; | ||
1329 | |||
1330 | bin_attr->size = 0; | ||
1331 | bin_attr->private = NULL; | ||
1332 | bin_attr->read = smp_portal_read; | ||
1333 | bin_attr->write= smp_portal_write; | ||
1334 | bin_attr->mmap = NULL; | ||
1335 | |||
1336 | ex_dev->smp_portal_pid = -1; | ||
1337 | init_MUTEX(&ex_dev->smp_sema); | ||
1338 | } | ||
1339 | #endif | ||
1340 | |||
1341 | /** | ||
1342 | * sas_discover_expander -- expander discovery | ||
1343 | * @ex: pointer to expander domain device | ||
1344 | * | ||
1345 | * See comment in sas_discover_sata(). | ||
1346 | */ | ||
1347 | static int sas_discover_expander(struct domain_device *dev) | ||
1348 | { | ||
1349 | int res; | ||
1350 | |||
1351 | res = sas_notify_lldd_dev_found(dev); | ||
1352 | if (res) | ||
1353 | return res; | ||
1354 | |||
1355 | res = sas_ex_general(dev); | ||
1356 | if (res) | ||
1357 | goto out_err; | ||
1358 | res = sas_ex_manuf_info(dev); | ||
1359 | if (res) | ||
1360 | goto out_err; | ||
1361 | |||
1362 | res = sas_expander_discover(dev); | ||
1363 | if (res) { | ||
1364 | SAS_DPRINTK("expander %016llx discovery failed(0x%x)\n", | ||
1365 | SAS_ADDR(dev->sas_addr), res); | ||
1366 | goto out_err; | ||
1367 | } | ||
1368 | |||
1369 | sas_check_ex_subtractive_boundary(dev); | ||
1370 | res = sas_check_parent_topology(dev); | ||
1371 | if (res) | ||
1372 | goto out_err; | ||
1373 | return 0; | ||
1374 | out_err: | ||
1375 | sas_notify_lldd_dev_gone(dev); | ||
1376 | return res; | ||
1377 | } | ||
1378 | |||
1379 | static int sas_ex_level_discovery(struct asd_sas_port *port, const int level) | ||
1380 | { | ||
1381 | int res = 0; | ||
1382 | struct domain_device *dev; | ||
1383 | |||
1384 | list_for_each_entry(dev, &port->dev_list, dev_list_node) { | ||
1385 | if (dev->dev_type == EDGE_DEV || | ||
1386 | dev->dev_type == FANOUT_DEV) { | ||
1387 | struct sas_expander_device *ex = | ||
1388 | rphy_to_expander_device(dev->rphy); | ||
1389 | |||
1390 | if (level == ex->level) | ||
1391 | res = sas_ex_discover_devices(dev, -1); | ||
1392 | else if (level > 0) | ||
1393 | res = sas_ex_discover_devices(port->port_dev, -1); | ||
1394 | |||
1395 | } | ||
1396 | } | ||
1397 | |||
1398 | return res; | ||
1399 | } | ||
1400 | |||
1401 | static int sas_ex_bfs_disc(struct asd_sas_port *port) | ||
1402 | { | ||
1403 | int res; | ||
1404 | int level; | ||
1405 | |||
1406 | do { | ||
1407 | level = port->disc.max_level; | ||
1408 | res = sas_ex_level_discovery(port, level); | ||
1409 | mb(); | ||
1410 | } while (level < port->disc.max_level); | ||
1411 | |||
1412 | return res; | ||
1413 | } | ||
1414 | |||
1415 | int sas_discover_root_expander(struct domain_device *dev) | ||
1416 | { | ||
1417 | int res; | ||
1418 | struct sas_expander_device *ex = rphy_to_expander_device(dev->rphy); | ||
1419 | |||
1420 | sas_rphy_add(dev->rphy); | ||
1421 | |||
1422 | ex->level = dev->port->disc.max_level; /* 0 */ | ||
1423 | res = sas_discover_expander(dev); | ||
1424 | if (!res) | ||
1425 | sas_ex_bfs_disc(dev->port); | ||
1426 | |||
1427 | return res; | ||
1428 | } | ||
1429 | |||
1430 | /* ---------- Domain revalidation ---------- */ | ||
1431 | |||
1432 | static int sas_get_phy_discover(struct domain_device *dev, | ||
1433 | int phy_id, struct smp_resp *disc_resp) | ||
1434 | { | ||
1435 | int res; | ||
1436 | u8 *disc_req; | ||
1437 | |||
1438 | disc_req = alloc_smp_req(DISCOVER_REQ_SIZE); | ||
1439 | if (!disc_req) | ||
1440 | return -ENOMEM; | ||
1441 | |||
1442 | disc_req[1] = SMP_DISCOVER; | ||
1443 | disc_req[9] = phy_id; | ||
1444 | |||
1445 | res = smp_execute_task(dev, disc_req, DISCOVER_REQ_SIZE, | ||
1446 | disc_resp, DISCOVER_RESP_SIZE); | ||
1447 | if (res) | ||
1448 | goto out; | ||
1449 | else if (disc_resp->result != SMP_RESP_FUNC_ACC) { | ||
1450 | res = disc_resp->result; | ||
1451 | goto out; | ||
1452 | } | ||
1453 | out: | ||
1454 | kfree(disc_req); | ||
1455 | return res; | ||
1456 | } | ||
1457 | |||
1458 | static int sas_get_phy_change_count(struct domain_device *dev, | ||
1459 | int phy_id, int *pcc) | ||
1460 | { | ||
1461 | int res; | ||
1462 | struct smp_resp *disc_resp; | ||
1463 | |||
1464 | disc_resp = alloc_smp_resp(DISCOVER_RESP_SIZE); | ||
1465 | if (!disc_resp) | ||
1466 | return -ENOMEM; | ||
1467 | |||
1468 | res = sas_get_phy_discover(dev, phy_id, disc_resp); | ||
1469 | if (!res) | ||
1470 | *pcc = disc_resp->disc.change_count; | ||
1471 | |||
1472 | kfree(disc_resp); | ||
1473 | return res; | ||
1474 | } | ||
1475 | |||
1476 | static int sas_get_phy_attached_sas_addr(struct domain_device *dev, | ||
1477 | int phy_id, u8 *attached_sas_addr) | ||
1478 | { | ||
1479 | int res; | ||
1480 | struct smp_resp *disc_resp; | ||
1481 | struct discover_resp *dr; | ||
1482 | |||
1483 | disc_resp = alloc_smp_resp(DISCOVER_RESP_SIZE); | ||
1484 | if (!disc_resp) | ||
1485 | return -ENOMEM; | ||
1486 | dr = &disc_resp->disc; | ||
1487 | |||
1488 | res = sas_get_phy_discover(dev, phy_id, disc_resp); | ||
1489 | if (!res) { | ||
1490 | memcpy(attached_sas_addr,disc_resp->disc.attached_sas_addr,8); | ||
1491 | if (dr->attached_dev_type == 0) | ||
1492 | memset(attached_sas_addr, 0, 8); | ||
1493 | } | ||
1494 | kfree(disc_resp); | ||
1495 | return res; | ||
1496 | } | ||
1497 | |||
1498 | static int sas_find_bcast_phy(struct domain_device *dev, int *phy_id, | ||
1499 | int from_phy) | ||
1500 | { | ||
1501 | struct expander_device *ex = &dev->ex_dev; | ||
1502 | int res = 0; | ||
1503 | int i; | ||
1504 | |||
1505 | for (i = from_phy; i < ex->num_phys; i++) { | ||
1506 | int phy_change_count = 0; | ||
1507 | |||
1508 | res = sas_get_phy_change_count(dev, i, &phy_change_count); | ||
1509 | if (res) | ||
1510 | goto out; | ||
1511 | else if (phy_change_count != ex->ex_phy[i].phy_change_count) { | ||
1512 | ex->ex_phy[i].phy_change_count = phy_change_count; | ||
1513 | *phy_id = i; | ||
1514 | return 0; | ||
1515 | } | ||
1516 | } | ||
1517 | out: | ||
1518 | return res; | ||
1519 | } | ||
1520 | |||
1521 | static int sas_get_ex_change_count(struct domain_device *dev, int *ecc) | ||
1522 | { | ||
1523 | int res; | ||
1524 | u8 *rg_req; | ||
1525 | struct smp_resp *rg_resp; | ||
1526 | |||
1527 | rg_req = alloc_smp_req(RG_REQ_SIZE); | ||
1528 | if (!rg_req) | ||
1529 | return -ENOMEM; | ||
1530 | |||
1531 | rg_resp = alloc_smp_resp(RG_RESP_SIZE); | ||
1532 | if (!rg_resp) { | ||
1533 | kfree(rg_req); | ||
1534 | return -ENOMEM; | ||
1535 | } | ||
1536 | |||
1537 | rg_req[1] = SMP_REPORT_GENERAL; | ||
1538 | |||
1539 | res = smp_execute_task(dev, rg_req, RG_REQ_SIZE, rg_resp, | ||
1540 | RG_RESP_SIZE); | ||
1541 | if (res) | ||
1542 | goto out; | ||
1543 | if (rg_resp->result != SMP_RESP_FUNC_ACC) { | ||
1544 | res = rg_resp->result; | ||
1545 | goto out; | ||
1546 | } | ||
1547 | |||
1548 | *ecc = be16_to_cpu(rg_resp->rg.change_count); | ||
1549 | out: | ||
1550 | kfree(rg_resp); | ||
1551 | kfree(rg_req); | ||
1552 | return res; | ||
1553 | } | ||
1554 | |||
1555 | static int sas_find_bcast_dev(struct domain_device *dev, | ||
1556 | struct domain_device **src_dev) | ||
1557 | { | ||
1558 | struct expander_device *ex = &dev->ex_dev; | ||
1559 | int ex_change_count = -1; | ||
1560 | int res; | ||
1561 | |||
1562 | res = sas_get_ex_change_count(dev, &ex_change_count); | ||
1563 | if (res) | ||
1564 | goto out; | ||
1565 | if (ex_change_count != -1 && | ||
1566 | ex_change_count != ex->ex_change_count) { | ||
1567 | *src_dev = dev; | ||
1568 | ex->ex_change_count = ex_change_count; | ||
1569 | } else { | ||
1570 | struct domain_device *ch; | ||
1571 | |||
1572 | list_for_each_entry(ch, &ex->children, siblings) { | ||
1573 | if (ch->dev_type == EDGE_DEV || | ||
1574 | ch->dev_type == FANOUT_DEV) { | ||
1575 | res = sas_find_bcast_dev(ch, src_dev); | ||
1576 | if (src_dev) | ||
1577 | return res; | ||
1578 | } | ||
1579 | } | ||
1580 | } | ||
1581 | out: | ||
1582 | return res; | ||
1583 | } | ||
1584 | |||
1585 | static void sas_unregister_ex_tree(struct domain_device *dev) | ||
1586 | { | ||
1587 | struct expander_device *ex = &dev->ex_dev; | ||
1588 | struct domain_device *child, *n; | ||
1589 | |||
1590 | list_for_each_entry_safe(child, n, &ex->children, siblings) { | ||
1591 | if (child->dev_type == EDGE_DEV || | ||
1592 | child->dev_type == FANOUT_DEV) | ||
1593 | sas_unregister_ex_tree(child); | ||
1594 | else | ||
1595 | sas_unregister_dev(child); | ||
1596 | } | ||
1597 | sas_unregister_dev(dev); | ||
1598 | } | ||
1599 | |||
1600 | static void sas_unregister_devs_sas_addr(struct domain_device *parent, | ||
1601 | int phy_id) | ||
1602 | { | ||
1603 | struct expander_device *ex_dev = &parent->ex_dev; | ||
1604 | struct ex_phy *phy = &ex_dev->ex_phy[phy_id]; | ||
1605 | struct domain_device *child, *n; | ||
1606 | |||
1607 | list_for_each_entry_safe(child, n, &ex_dev->children, siblings) { | ||
1608 | if (SAS_ADDR(child->sas_addr) == | ||
1609 | SAS_ADDR(phy->attached_sas_addr)) { | ||
1610 | if (child->dev_type == EDGE_DEV || | ||
1611 | child->dev_type == FANOUT_DEV) | ||
1612 | sas_unregister_ex_tree(child); | ||
1613 | else | ||
1614 | sas_unregister_dev(child); | ||
1615 | break; | ||
1616 | } | ||
1617 | } | ||
1618 | sas_disable_routing(parent, phy->attached_sas_addr); | ||
1619 | memset(phy->attached_sas_addr, 0, SAS_ADDR_SIZE); | ||
1620 | sas_port_delete_phy(phy->port, phy->phy); | ||
1621 | if (phy->port->num_phys == 0) | ||
1622 | sas_port_delete(phy->port); | ||
1623 | phy->port = NULL; | ||
1624 | } | ||
1625 | |||
1626 | static int sas_discover_bfs_by_root_level(struct domain_device *root, | ||
1627 | const int level) | ||
1628 | { | ||
1629 | struct expander_device *ex_root = &root->ex_dev; | ||
1630 | struct domain_device *child; | ||
1631 | int res = 0; | ||
1632 | |||
1633 | list_for_each_entry(child, &ex_root->children, siblings) { | ||
1634 | if (child->dev_type == EDGE_DEV || | ||
1635 | child->dev_type == FANOUT_DEV) { | ||
1636 | struct sas_expander_device *ex = | ||
1637 | rphy_to_expander_device(child->rphy); | ||
1638 | |||
1639 | if (level > ex->level) | ||
1640 | res = sas_discover_bfs_by_root_level(child, | ||
1641 | level); | ||
1642 | else if (level == ex->level) | ||
1643 | res = sas_ex_discover_devices(child, -1); | ||
1644 | } | ||
1645 | } | ||
1646 | return res; | ||
1647 | } | ||
1648 | |||
1649 | static int sas_discover_bfs_by_root(struct domain_device *dev) | ||
1650 | { | ||
1651 | int res; | ||
1652 | struct sas_expander_device *ex = rphy_to_expander_device(dev->rphy); | ||
1653 | int level = ex->level+1; | ||
1654 | |||
1655 | res = sas_ex_discover_devices(dev, -1); | ||
1656 | if (res) | ||
1657 | goto out; | ||
1658 | do { | ||
1659 | res = sas_discover_bfs_by_root_level(dev, level); | ||
1660 | mb(); | ||
1661 | level += 1; | ||
1662 | } while (level <= dev->port->disc.max_level); | ||
1663 | out: | ||
1664 | return res; | ||
1665 | } | ||
1666 | |||
1667 | static int sas_discover_new(struct domain_device *dev, int phy_id) | ||
1668 | { | ||
1669 | struct ex_phy *ex_phy = &dev->ex_dev.ex_phy[phy_id]; | ||
1670 | struct domain_device *child; | ||
1671 | int res; | ||
1672 | |||
1673 | SAS_DPRINTK("ex %016llx phy%d new device attached\n", | ||
1674 | SAS_ADDR(dev->sas_addr), phy_id); | ||
1675 | res = sas_ex_phy_discover(dev, phy_id); | ||
1676 | if (res) | ||
1677 | goto out; | ||
1678 | res = sas_ex_discover_devices(dev, phy_id); | ||
1679 | if (res) | ||
1680 | goto out; | ||
1681 | list_for_each_entry(child, &dev->ex_dev.children, siblings) { | ||
1682 | if (SAS_ADDR(child->sas_addr) == | ||
1683 | SAS_ADDR(ex_phy->attached_sas_addr)) { | ||
1684 | if (child->dev_type == EDGE_DEV || | ||
1685 | child->dev_type == FANOUT_DEV) | ||
1686 | res = sas_discover_bfs_by_root(child); | ||
1687 | break; | ||
1688 | } | ||
1689 | } | ||
1690 | out: | ||
1691 | return res; | ||
1692 | } | ||
1693 | |||
1694 | static int sas_rediscover_dev(struct domain_device *dev, int phy_id) | ||
1695 | { | ||
1696 | struct expander_device *ex = &dev->ex_dev; | ||
1697 | struct ex_phy *phy = &ex->ex_phy[phy_id]; | ||
1698 | u8 attached_sas_addr[8]; | ||
1699 | int res; | ||
1700 | |||
1701 | res = sas_get_phy_attached_sas_addr(dev, phy_id, attached_sas_addr); | ||
1702 | switch (res) { | ||
1703 | case SMP_RESP_NO_PHY: | ||
1704 | phy->phy_state = PHY_NOT_PRESENT; | ||
1705 | sas_unregister_devs_sas_addr(dev, phy_id); | ||
1706 | goto out; break; | ||
1707 | case SMP_RESP_PHY_VACANT: | ||
1708 | phy->phy_state = PHY_VACANT; | ||
1709 | sas_unregister_devs_sas_addr(dev, phy_id); | ||
1710 | goto out; break; | ||
1711 | case SMP_RESP_FUNC_ACC: | ||
1712 | break; | ||
1713 | } | ||
1714 | |||
1715 | if (SAS_ADDR(attached_sas_addr) == 0) { | ||
1716 | phy->phy_state = PHY_EMPTY; | ||
1717 | sas_unregister_devs_sas_addr(dev, phy_id); | ||
1718 | } else if (SAS_ADDR(attached_sas_addr) == | ||
1719 | SAS_ADDR(phy->attached_sas_addr)) { | ||
1720 | SAS_DPRINTK("ex %016llx phy 0x%x broadcast flutter\n", | ||
1721 | SAS_ADDR(dev->sas_addr), phy_id); | ||
1722 | } else | ||
1723 | res = sas_discover_new(dev, phy_id); | ||
1724 | out: | ||
1725 | return res; | ||
1726 | } | ||
1727 | |||
1728 | static int sas_rediscover(struct domain_device *dev, const int phy_id) | ||
1729 | { | ||
1730 | struct expander_device *ex = &dev->ex_dev; | ||
1731 | struct ex_phy *changed_phy = &ex->ex_phy[phy_id]; | ||
1732 | int res = 0; | ||
1733 | int i; | ||
1734 | |||
1735 | SAS_DPRINTK("ex %016llx phy%d originated BROADCAST(CHANGE)\n", | ||
1736 | SAS_ADDR(dev->sas_addr), phy_id); | ||
1737 | |||
1738 | if (SAS_ADDR(changed_phy->attached_sas_addr) != 0) { | ||
1739 | for (i = 0; i < ex->num_phys; i++) { | ||
1740 | struct ex_phy *phy = &ex->ex_phy[i]; | ||
1741 | |||
1742 | if (i == phy_id) | ||
1743 | continue; | ||
1744 | if (SAS_ADDR(phy->attached_sas_addr) == | ||
1745 | SAS_ADDR(changed_phy->attached_sas_addr)) { | ||
1746 | SAS_DPRINTK("phy%d part of wide port with " | ||
1747 | "phy%d\n", phy_id, i); | ||
1748 | goto out; | ||
1749 | } | ||
1750 | } | ||
1751 | res = sas_rediscover_dev(dev, phy_id); | ||
1752 | } else | ||
1753 | res = sas_discover_new(dev, phy_id); | ||
1754 | out: | ||
1755 | return res; | ||
1756 | } | ||
1757 | |||
1758 | /** | ||
1759 | * sas_revalidate_domain -- revalidate the domain | ||
1760 | * @port: port to the domain of interest | ||
1761 | * | ||
1762 | * NOTE: this process _must_ quit (return) as soon as any connection | ||
1763 | * errors are encountered. Connection recovery is done elsewhere. | ||
1764 | * Discover process only interrogates devices in order to discover the | ||
1765 | * domain. | ||
1766 | */ | ||
1767 | int sas_ex_revalidate_domain(struct domain_device *port_dev) | ||
1768 | { | ||
1769 | int res; | ||
1770 | struct domain_device *dev = NULL; | ||
1771 | |||
1772 | res = sas_find_bcast_dev(port_dev, &dev); | ||
1773 | if (res) | ||
1774 | goto out; | ||
1775 | if (dev) { | ||
1776 | struct expander_device *ex = &dev->ex_dev; | ||
1777 | int i = 0, phy_id; | ||
1778 | |||
1779 | do { | ||
1780 | phy_id = -1; | ||
1781 | res = sas_find_bcast_phy(dev, &phy_id, i); | ||
1782 | if (phy_id == -1) | ||
1783 | break; | ||
1784 | res = sas_rediscover(dev, phy_id); | ||
1785 | i = phy_id + 1; | ||
1786 | } while (i < ex->num_phys); | ||
1787 | } | ||
1788 | out: | ||
1789 | return res; | ||
1790 | } | ||
1791 | |||
1792 | #if 0 | ||
1793 | /* ---------- SMP portal ---------- */ | ||
1794 | |||
1795 | static ssize_t smp_portal_write(struct kobject *kobj, char *buf, loff_t offs, | ||
1796 | size_t size) | ||
1797 | { | ||
1798 | struct domain_device *dev = to_dom_device(kobj); | ||
1799 | struct expander_device *ex = &dev->ex_dev; | ||
1800 | |||
1801 | if (offs != 0) | ||
1802 | return -EFBIG; | ||
1803 | else if (size == 0) | ||
1804 | return 0; | ||
1805 | |||
1806 | down_interruptible(&ex->smp_sema); | ||
1807 | if (ex->smp_req) | ||
1808 | kfree(ex->smp_req); | ||
1809 | ex->smp_req = kzalloc(size, GFP_USER); | ||
1810 | if (!ex->smp_req) { | ||
1811 | up(&ex->smp_sema); | ||
1812 | return -ENOMEM; | ||
1813 | } | ||
1814 | memcpy(ex->smp_req, buf, size); | ||
1815 | ex->smp_req_size = size; | ||
1816 | ex->smp_portal_pid = current->pid; | ||
1817 | up(&ex->smp_sema); | ||
1818 | |||
1819 | return size; | ||
1820 | } | ||
1821 | |||
1822 | static ssize_t smp_portal_read(struct kobject *kobj, char *buf, loff_t offs, | ||
1823 | size_t size) | ||
1824 | { | ||
1825 | struct domain_device *dev = to_dom_device(kobj); | ||
1826 | struct expander_device *ex = &dev->ex_dev; | ||
1827 | u8 *smp_resp; | ||
1828 | int res = -EINVAL; | ||
1829 | |||
1830 | /* XXX: sysfs gives us an offset of 0x10 or 0x8 while in fact | ||
1831 | * it should be 0. | ||
1832 | */ | ||
1833 | |||
1834 | down_interruptible(&ex->smp_sema); | ||
1835 | if (!ex->smp_req || ex->smp_portal_pid != current->pid) | ||
1836 | goto out; | ||
1837 | |||
1838 | res = 0; | ||
1839 | if (size == 0) | ||
1840 | goto out; | ||
1841 | |||
1842 | res = -ENOMEM; | ||
1843 | smp_resp = alloc_smp_resp(size); | ||
1844 | if (!smp_resp) | ||
1845 | goto out; | ||
1846 | res = smp_execute_task(dev, ex->smp_req, ex->smp_req_size, | ||
1847 | smp_resp, size); | ||
1848 | if (!res) { | ||
1849 | memcpy(buf, smp_resp, size); | ||
1850 | res = size; | ||
1851 | } | ||
1852 | |||
1853 | kfree(smp_resp); | ||
1854 | out: | ||
1855 | kfree(ex->smp_req); | ||
1856 | ex->smp_req = NULL; | ||
1857 | ex->smp_req_size = 0; | ||
1858 | ex->smp_portal_pid = -1; | ||
1859 | up(&ex->smp_sema); | ||
1860 | return res; | ||
1861 | } | ||
1862 | #endif | ||
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c new file mode 100644 index 000000000000..b961664b8106 --- /dev/null +++ b/drivers/scsi/libsas/sas_init.c | |||
@@ -0,0 +1,227 @@ | |||
1 | /* | ||
2 | * Serial Attached SCSI (SAS) Transport Layer initialization | ||
3 | * | ||
4 | * Copyright (C) 2005 Adaptec, Inc. All rights reserved. | ||
5 | * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> | ||
6 | * | ||
7 | * This file is licensed under GPLv2. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License as | ||
11 | * published by the Free Software Foundation; either version 2 of the | ||
12 | * License, or (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | ||
22 | * USA | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #include <linux/module.h> | ||
27 | #include <linux/init.h> | ||
28 | #include <linux/device.h> | ||
29 | #include <linux/spinlock.h> | ||
30 | #include <scsi/scsi_host.h> | ||
31 | #include <scsi/scsi_device.h> | ||
32 | #include <scsi/scsi_transport.h> | ||
33 | #include <scsi/scsi_transport_sas.h> | ||
34 | |||
35 | #include "sas_internal.h" | ||
36 | |||
37 | #include "../scsi_sas_internal.h" | ||
38 | |||
39 | kmem_cache_t *sas_task_cache; | ||
40 | |||
41 | /*------------ SAS addr hash -----------*/ | ||
42 | void sas_hash_addr(u8 *hashed, const u8 *sas_addr) | ||
43 | { | ||
44 | const u32 poly = 0x00DB2777; | ||
45 | u32 r = 0; | ||
46 | int i; | ||
47 | |||
48 | for (i = 0; i < 8; i++) { | ||
49 | int b; | ||
50 | for (b = 7; b >= 0; b--) { | ||
51 | r <<= 1; | ||
52 | if ((1 << b) & sas_addr[i]) { | ||
53 | if (!(r & 0x01000000)) | ||
54 | r ^= poly; | ||
55 | } else if (r & 0x01000000) | ||
56 | r ^= poly; | ||
57 | } | ||
58 | } | ||
59 | |||
60 | hashed[0] = (r >> 16) & 0xFF; | ||
61 | hashed[1] = (r >> 8) & 0xFF ; | ||
62 | hashed[2] = r & 0xFF; | ||
63 | } | ||
64 | |||
65 | |||
66 | /* ---------- HA events ---------- */ | ||
67 | |||
68 | void sas_hae_reset(void *data) | ||
69 | { | ||
70 | struct sas_ha_struct *ha = data; | ||
71 | |||
72 | sas_begin_event(HAE_RESET, &ha->event_lock, | ||
73 | &ha->pending); | ||
74 | } | ||
75 | |||
76 | int sas_register_ha(struct sas_ha_struct *sas_ha) | ||
77 | { | ||
78 | int error = 0; | ||
79 | |||
80 | spin_lock_init(&sas_ha->phy_port_lock); | ||
81 | sas_hash_addr(sas_ha->hashed_sas_addr, sas_ha->sas_addr); | ||
82 | |||
83 | if (sas_ha->lldd_queue_size == 0) | ||
84 | sas_ha->lldd_queue_size = 1; | ||
85 | else if (sas_ha->lldd_queue_size == -1) | ||
86 | sas_ha->lldd_queue_size = 128; /* Sanity */ | ||
87 | |||
88 | error = sas_register_phys(sas_ha); | ||
89 | if (error) { | ||
90 | printk(KERN_NOTICE "couldn't register sas phys:%d\n", error); | ||
91 | return error; | ||
92 | } | ||
93 | |||
94 | error = sas_register_ports(sas_ha); | ||
95 | if (error) { | ||
96 | printk(KERN_NOTICE "couldn't register sas ports:%d\n", error); | ||
97 | goto Undo_phys; | ||
98 | } | ||
99 | |||
100 | error = sas_init_events(sas_ha); | ||
101 | if (error) { | ||
102 | printk(KERN_NOTICE "couldn't start event thread:%d\n", error); | ||
103 | goto Undo_ports; | ||
104 | } | ||
105 | |||
106 | if (sas_ha->lldd_max_execute_num > 1) { | ||
107 | error = sas_init_queue(sas_ha); | ||
108 | if (error) { | ||
109 | printk(KERN_NOTICE "couldn't start queue thread:%d, " | ||
110 | "running in direct mode\n", error); | ||
111 | sas_ha->lldd_max_execute_num = 1; | ||
112 | } | ||
113 | } | ||
114 | |||
115 | return 0; | ||
116 | |||
117 | Undo_ports: | ||
118 | sas_unregister_ports(sas_ha); | ||
119 | Undo_phys: | ||
120 | |||
121 | return error; | ||
122 | } | ||
123 | |||
124 | int sas_unregister_ha(struct sas_ha_struct *sas_ha) | ||
125 | { | ||
126 | if (sas_ha->lldd_max_execute_num > 1) { | ||
127 | sas_shutdown_queue(sas_ha); | ||
128 | } | ||
129 | |||
130 | sas_unregister_ports(sas_ha); | ||
131 | |||
132 | return 0; | ||
133 | } | ||
134 | |||
135 | static int sas_get_linkerrors(struct sas_phy *phy) | ||
136 | { | ||
137 | if (scsi_is_sas_phy_local(phy)) | ||
138 | /* FIXME: we have no local phy stats | ||
139 | * gathering at this time */ | ||
140 | return -EINVAL; | ||
141 | |||
142 | return sas_smp_get_phy_events(phy); | ||
143 | } | ||
144 | |||
145 | static int sas_phy_reset(struct sas_phy *phy, int hard_reset) | ||
146 | { | ||
147 | int ret; | ||
148 | enum phy_func reset_type; | ||
149 | |||
150 | if (hard_reset) | ||
151 | reset_type = PHY_FUNC_HARD_RESET; | ||
152 | else | ||
153 | reset_type = PHY_FUNC_LINK_RESET; | ||
154 | |||
155 | if (scsi_is_sas_phy_local(phy)) { | ||
156 | struct Scsi_Host *shost = dev_to_shost(phy->dev.parent); | ||
157 | struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost); | ||
158 | struct asd_sas_phy *asd_phy = sas_ha->sas_phy[phy->number]; | ||
159 | struct sas_internal *i = | ||
160 | to_sas_internal(sas_ha->core.shost->transportt); | ||
161 | |||
162 | ret = i->dft->lldd_control_phy(asd_phy, reset_type); | ||
163 | } else { | ||
164 | struct sas_rphy *rphy = dev_to_rphy(phy->dev.parent); | ||
165 | struct domain_device *ddev = sas_find_dev_by_rphy(rphy); | ||
166 | ret = sas_smp_phy_control(ddev, phy->number, reset_type); | ||
167 | } | ||
168 | return ret; | ||
169 | } | ||
170 | |||
171 | static struct sas_function_template sft = { | ||
172 | .phy_reset = sas_phy_reset, | ||
173 | .get_linkerrors = sas_get_linkerrors, | ||
174 | }; | ||
175 | |||
176 | struct scsi_transport_template * | ||
177 | sas_domain_attach_transport(struct sas_domain_function_template *dft) | ||
178 | { | ||
179 | struct scsi_transport_template *stt = sas_attach_transport(&sft); | ||
180 | struct sas_internal *i; | ||
181 | |||
182 | if (!stt) | ||
183 | return stt; | ||
184 | |||
185 | i = to_sas_internal(stt); | ||
186 | i->dft = dft; | ||
187 | stt->create_work_queue = 1; | ||
188 | stt->eh_timed_out = sas_scsi_timed_out; | ||
189 | stt->eh_strategy_handler = sas_scsi_recover_host; | ||
190 | |||
191 | return stt; | ||
192 | } | ||
193 | EXPORT_SYMBOL_GPL(sas_domain_attach_transport); | ||
194 | |||
195 | |||
196 | void sas_domain_release_transport(struct scsi_transport_template *stt) | ||
197 | { | ||
198 | sas_release_transport(stt); | ||
199 | } | ||
200 | EXPORT_SYMBOL_GPL(sas_domain_release_transport); | ||
201 | |||
202 | /* ---------- SAS Class register/unregister ---------- */ | ||
203 | |||
204 | static int __init sas_class_init(void) | ||
205 | { | ||
206 | sas_task_cache = kmem_cache_create("sas_task", sizeof(struct sas_task), | ||
207 | 0, SLAB_HWCACHE_ALIGN, NULL, NULL); | ||
208 | if (!sas_task_cache) | ||
209 | return -ENOMEM; | ||
210 | |||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | static void __exit sas_class_exit(void) | ||
215 | { | ||
216 | kmem_cache_destroy(sas_task_cache); | ||
217 | } | ||
218 | |||
219 | MODULE_AUTHOR("Luben Tuikov <luben_tuikov@adaptec.com>"); | ||
220 | MODULE_DESCRIPTION("SAS Transport Layer"); | ||
221 | MODULE_LICENSE("GPL v2"); | ||
222 | |||
223 | module_init(sas_class_init); | ||
224 | module_exit(sas_class_exit); | ||
225 | |||
226 | EXPORT_SYMBOL_GPL(sas_register_ha); | ||
227 | EXPORT_SYMBOL_GPL(sas_unregister_ha); | ||
diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h new file mode 100644 index 000000000000..89c397680846 --- /dev/null +++ b/drivers/scsi/libsas/sas_internal.h | |||
@@ -0,0 +1,146 @@ | |||
1 | /* | ||
2 | * Serial Attached SCSI (SAS) class internal header file | ||
3 | * | ||
4 | * Copyright (C) 2005 Adaptec, Inc. All rights reserved. | ||
5 | * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> | ||
6 | * | ||
7 | * This file is licensed under GPLv2. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License as | ||
11 | * published by the Free Software Foundation; either version 2 of the | ||
12 | * License, or (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | ||
22 | * USA | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #ifndef _SAS_INTERNAL_H_ | ||
27 | #define _SAS_INTERNAL_H_ | ||
28 | |||
29 | #include <scsi/scsi.h> | ||
30 | #include <scsi/scsi_host.h> | ||
31 | #include <scsi/scsi_transport_sas.h> | ||
32 | #include <scsi/libsas.h> | ||
33 | |||
34 | #define sas_printk(fmt, ...) printk(KERN_NOTICE "sas: " fmt, ## __VA_ARGS__) | ||
35 | |||
36 | #ifdef SAS_DEBUG | ||
37 | #define SAS_DPRINTK(fmt, ...) printk(KERN_NOTICE "sas: " fmt, ## __VA_ARGS__) | ||
38 | #else | ||
39 | #define SAS_DPRINTK(fmt, ...) | ||
40 | #endif | ||
41 | |||
42 | void sas_scsi_recover_host(struct Scsi_Host *shost); | ||
43 | |||
44 | int sas_show_class(enum sas_class class, char *buf); | ||
45 | int sas_show_proto(enum sas_proto proto, char *buf); | ||
46 | int sas_show_linkrate(enum sas_phy_linkrate linkrate, char *buf); | ||
47 | int sas_show_oob_mode(enum sas_oob_mode oob_mode, char *buf); | ||
48 | |||
49 | int sas_register_phys(struct sas_ha_struct *sas_ha); | ||
50 | void sas_unregister_phys(struct sas_ha_struct *sas_ha); | ||
51 | |||
52 | int sas_register_ports(struct sas_ha_struct *sas_ha); | ||
53 | void sas_unregister_ports(struct sas_ha_struct *sas_ha); | ||
54 | |||
55 | enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *); | ||
56 | |||
57 | int sas_init_queue(struct sas_ha_struct *sas_ha); | ||
58 | int sas_init_events(struct sas_ha_struct *sas_ha); | ||
59 | void sas_shutdown_queue(struct sas_ha_struct *sas_ha); | ||
60 | |||
61 | void sas_deform_port(struct asd_sas_phy *phy); | ||
62 | |||
63 | void sas_porte_bytes_dmaed(void *); | ||
64 | void sas_porte_broadcast_rcvd(void *); | ||
65 | void sas_porte_link_reset_err(void *); | ||
66 | void sas_porte_timer_event(void *); | ||
67 | void sas_porte_hard_reset(void *); | ||
68 | |||
69 | int sas_notify_lldd_dev_found(struct domain_device *); | ||
70 | void sas_notify_lldd_dev_gone(struct domain_device *); | ||
71 | |||
72 | int sas_smp_phy_control(struct domain_device *dev, int phy_id, | ||
73 | enum phy_func phy_func); | ||
74 | int sas_smp_get_phy_events(struct sas_phy *phy); | ||
75 | |||
76 | struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy); | ||
77 | |||
78 | void sas_hae_reset(void *); | ||
79 | |||
80 | static inline void sas_queue_event(int event, spinlock_t *lock, | ||
81 | unsigned long *pending, | ||
82 | struct work_struct *work, | ||
83 | struct Scsi_Host *shost) | ||
84 | { | ||
85 | unsigned long flags; | ||
86 | |||
87 | spin_lock_irqsave(lock, flags); | ||
88 | if (test_bit(event, pending)) { | ||
89 | spin_unlock_irqrestore(lock, flags); | ||
90 | return; | ||
91 | } | ||
92 | __set_bit(event, pending); | ||
93 | spin_unlock_irqrestore(lock, flags); | ||
94 | scsi_queue_work(shost, work); | ||
95 | } | ||
96 | |||
97 | static inline void sas_begin_event(int event, spinlock_t *lock, | ||
98 | unsigned long *pending) | ||
99 | { | ||
100 | unsigned long flags; | ||
101 | |||
102 | spin_lock_irqsave(lock, flags); | ||
103 | __clear_bit(event, pending); | ||
104 | spin_unlock_irqrestore(lock, flags); | ||
105 | } | ||
106 | |||
107 | static inline void sas_fill_in_rphy(struct domain_device *dev, | ||
108 | struct sas_rphy *rphy) | ||
109 | { | ||
110 | rphy->identify.sas_address = SAS_ADDR(dev->sas_addr); | ||
111 | rphy->identify.initiator_port_protocols = dev->iproto; | ||
112 | rphy->identify.target_port_protocols = dev->tproto; | ||
113 | switch (dev->dev_type) { | ||
114 | case SATA_DEV: | ||
115 | /* FIXME: need sata device type */ | ||
116 | case SAS_END_DEV: | ||
117 | rphy->identify.device_type = SAS_END_DEVICE; | ||
118 | break; | ||
119 | case EDGE_DEV: | ||
120 | rphy->identify.device_type = SAS_EDGE_EXPANDER_DEVICE; | ||
121 | break; | ||
122 | case FANOUT_DEV: | ||
123 | rphy->identify.device_type = SAS_FANOUT_EXPANDER_DEVICE; | ||
124 | break; | ||
125 | default: | ||
126 | rphy->identify.device_type = SAS_PHY_UNUSED; | ||
127 | break; | ||
128 | } | ||
129 | } | ||
130 | |||
131 | static inline void sas_add_parent_port(struct domain_device *dev, int phy_id) | ||
132 | { | ||
133 | struct expander_device *ex = &dev->ex_dev; | ||
134 | struct ex_phy *ex_phy = &ex->ex_phy[phy_id]; | ||
135 | |||
136 | if (!ex->parent_port) { | ||
137 | ex->parent_port = sas_port_alloc(&dev->rphy->dev, phy_id); | ||
138 | /* FIXME: error handling */ | ||
139 | BUG_ON(!ex->parent_port); | ||
140 | BUG_ON(sas_port_add(ex->parent_port)); | ||
141 | sas_port_mark_backlink(ex->parent_port); | ||
142 | } | ||
143 | sas_port_add_phy(ex->parent_port, ex_phy->phy); | ||
144 | } | ||
145 | |||
146 | #endif /* _SAS_INTERNAL_H_ */ | ||
diff --git a/drivers/scsi/libsas/sas_phy.c b/drivers/scsi/libsas/sas_phy.c new file mode 100644 index 000000000000..024ab00e70d2 --- /dev/null +++ b/drivers/scsi/libsas/sas_phy.c | |||
@@ -0,0 +1,157 @@ | |||
1 | /* | ||
2 | * Serial Attached SCSI (SAS) Phy class | ||
3 | * | ||
4 | * Copyright (C) 2005 Adaptec, Inc. All rights reserved. | ||
5 | * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> | ||
6 | * | ||
7 | * This file is licensed under GPLv2. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License as | ||
11 | * published by the Free Software Foundation; either version 2 of the | ||
12 | * License, or (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #include "sas_internal.h" | ||
26 | #include <scsi/scsi_host.h> | ||
27 | #include <scsi/scsi_transport.h> | ||
28 | #include <scsi/scsi_transport_sas.h> | ||
29 | #include "../scsi_sas_internal.h" | ||
30 | |||
31 | /* ---------- Phy events ---------- */ | ||
32 | |||
33 | static void sas_phye_loss_of_signal(void *data) | ||
34 | { | ||
35 | struct asd_sas_phy *phy = data; | ||
36 | |||
37 | sas_begin_event(PHYE_LOSS_OF_SIGNAL, &phy->ha->event_lock, | ||
38 | &phy->phy_events_pending); | ||
39 | phy->error = 0; | ||
40 | sas_deform_port(phy); | ||
41 | } | ||
42 | |||
43 | static void sas_phye_oob_done(void *data) | ||
44 | { | ||
45 | struct asd_sas_phy *phy = data; | ||
46 | |||
47 | sas_begin_event(PHYE_OOB_DONE, &phy->ha->event_lock, | ||
48 | &phy->phy_events_pending); | ||
49 | phy->error = 0; | ||
50 | } | ||
51 | |||
52 | static void sas_phye_oob_error(void *data) | ||
53 | { | ||
54 | struct asd_sas_phy *phy = data; | ||
55 | struct sas_ha_struct *sas_ha = phy->ha; | ||
56 | struct asd_sas_port *port = phy->port; | ||
57 | struct sas_internal *i = | ||
58 | to_sas_internal(sas_ha->core.shost->transportt); | ||
59 | |||
60 | sas_begin_event(PHYE_OOB_ERROR, &phy->ha->event_lock, | ||
61 | &phy->phy_events_pending); | ||
62 | |||
63 | sas_deform_port(phy); | ||
64 | |||
65 | if (!port && phy->enabled && i->dft->lldd_control_phy) { | ||
66 | phy->error++; | ||
67 | switch (phy->error) { | ||
68 | case 1: | ||
69 | case 2: | ||
70 | i->dft->lldd_control_phy(phy, PHY_FUNC_HARD_RESET); | ||
71 | break; | ||
72 | case 3: | ||
73 | default: | ||
74 | phy->error = 0; | ||
75 | phy->enabled = 0; | ||
76 | i->dft->lldd_control_phy(phy, PHY_FUNC_DISABLE); | ||
77 | break; | ||
78 | } | ||
79 | } | ||
80 | } | ||
81 | |||
82 | static void sas_phye_spinup_hold(void *data) | ||
83 | { | ||
84 | struct asd_sas_phy *phy = data; | ||
85 | struct sas_ha_struct *sas_ha = phy->ha; | ||
86 | struct sas_internal *i = | ||
87 | to_sas_internal(sas_ha->core.shost->transportt); | ||
88 | |||
89 | sas_begin_event(PHYE_SPINUP_HOLD, &phy->ha->event_lock, | ||
90 | &phy->phy_events_pending); | ||
91 | |||
92 | phy->error = 0; | ||
93 | i->dft->lldd_control_phy(phy, PHY_FUNC_RELEASE_SPINUP_HOLD); | ||
94 | } | ||
95 | |||
96 | /* ---------- Phy class registration ---------- */ | ||
97 | |||
98 | int sas_register_phys(struct sas_ha_struct *sas_ha) | ||
99 | { | ||
100 | int i; | ||
101 | |||
102 | static void (*sas_phy_event_fns[PHY_NUM_EVENTS])(void *) = { | ||
103 | [PHYE_LOSS_OF_SIGNAL] = sas_phye_loss_of_signal, | ||
104 | [PHYE_OOB_DONE] = sas_phye_oob_done, | ||
105 | [PHYE_OOB_ERROR] = sas_phye_oob_error, | ||
106 | [PHYE_SPINUP_HOLD] = sas_phye_spinup_hold, | ||
107 | }; | ||
108 | |||
109 | static void (*sas_port_event_fns[PORT_NUM_EVENTS])(void *) = { | ||
110 | [PORTE_BYTES_DMAED] = sas_porte_bytes_dmaed, | ||
111 | [PORTE_BROADCAST_RCVD] = sas_porte_broadcast_rcvd, | ||
112 | [PORTE_LINK_RESET_ERR] = sas_porte_link_reset_err, | ||
113 | [PORTE_TIMER_EVENT] = sas_porte_timer_event, | ||
114 | [PORTE_HARD_RESET] = sas_porte_hard_reset, | ||
115 | }; | ||
116 | |||
117 | /* Now register the phys. */ | ||
118 | for (i = 0; i < sas_ha->num_phys; i++) { | ||
119 | int k; | ||
120 | struct asd_sas_phy *phy = sas_ha->sas_phy[i]; | ||
121 | |||
122 | phy->error = 0; | ||
123 | INIT_LIST_HEAD(&phy->port_phy_el); | ||
124 | for (k = 0; k < PORT_NUM_EVENTS; k++) | ||
125 | INIT_WORK(&phy->port_events[k], sas_port_event_fns[k], | ||
126 | phy); | ||
127 | |||
128 | for (k = 0; k < PHY_NUM_EVENTS; k++) | ||
129 | INIT_WORK(&phy->phy_events[k], sas_phy_event_fns[k], | ||
130 | phy); | ||
131 | phy->port = NULL; | ||
132 | phy->ha = sas_ha; | ||
133 | spin_lock_init(&phy->frame_rcvd_lock); | ||
134 | spin_lock_init(&phy->sas_prim_lock); | ||
135 | phy->frame_rcvd_size = 0; | ||
136 | |||
137 | phy->phy = sas_phy_alloc(&sas_ha->core.shost->shost_gendev, | ||
138 | i); | ||
139 | if (!phy->phy) | ||
140 | return -ENOMEM; | ||
141 | |||
142 | phy->phy->identify.initiator_port_protocols = | ||
143 | phy->iproto; | ||
144 | phy->phy->identify.target_port_protocols = phy->tproto; | ||
145 | phy->phy->identify.sas_address = SAS_ADDR(sas_ha->sas_addr); | ||
146 | phy->phy->identify.phy_identifier = i; | ||
147 | phy->phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS; | ||
148 | phy->phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS; | ||
149 | phy->phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS; | ||
150 | phy->phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS; | ||
151 | phy->phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN; | ||
152 | |||
153 | sas_phy_add(phy->phy); | ||
154 | } | ||
155 | |||
156 | return 0; | ||
157 | } | ||
diff --git a/drivers/scsi/libsas/sas_port.c b/drivers/scsi/libsas/sas_port.c new file mode 100644 index 000000000000..253cdcf306a2 --- /dev/null +++ b/drivers/scsi/libsas/sas_port.c | |||
@@ -0,0 +1,279 @@ | |||
1 | /* | ||
2 | * Serial Attached SCSI (SAS) Port class | ||
3 | * | ||
4 | * Copyright (C) 2005 Adaptec, Inc. All rights reserved. | ||
5 | * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> | ||
6 | * | ||
7 | * This file is licensed under GPLv2. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License as | ||
11 | * published by the Free Software Foundation; either version 2 of the | ||
12 | * License, or (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #include "sas_internal.h" | ||
26 | |||
27 | #include <scsi/scsi_transport.h> | ||
28 | #include <scsi/scsi_transport_sas.h> | ||
29 | #include "../scsi_sas_internal.h" | ||
30 | |||
31 | /** | ||
32 | * sas_form_port -- add this phy to a port | ||
33 | * @phy: the phy of interest | ||
34 | * | ||
35 | * This function adds this phy to an existing port, thus creating a wide | ||
36 | * port, or it creates a port and adds the phy to the port. | ||
37 | */ | ||
38 | static void sas_form_port(struct asd_sas_phy *phy) | ||
39 | { | ||
40 | int i; | ||
41 | struct sas_ha_struct *sas_ha = phy->ha; | ||
42 | struct asd_sas_port *port = phy->port; | ||
43 | struct sas_internal *si = | ||
44 | to_sas_internal(sas_ha->core.shost->transportt); | ||
45 | |||
46 | if (port) { | ||
47 | if (memcmp(port->attached_sas_addr, phy->attached_sas_addr, | ||
48 | SAS_ADDR_SIZE) == 0) | ||
49 | sas_deform_port(phy); | ||
50 | else { | ||
51 | SAS_DPRINTK("%s: phy%d belongs to port%d already(%d)!\n", | ||
52 | __FUNCTION__, phy->id, phy->port->id, | ||
53 | phy->port->num_phys); | ||
54 | return; | ||
55 | } | ||
56 | } | ||
57 | |||
58 | /* find a port */ | ||
59 | spin_lock(&sas_ha->phy_port_lock); | ||
60 | for (i = 0; i < sas_ha->num_phys; i++) { | ||
61 | port = sas_ha->sas_port[i]; | ||
62 | spin_lock(&port->phy_list_lock); | ||
63 | if (*(u64 *) port->sas_addr && | ||
64 | memcmp(port->attached_sas_addr, | ||
65 | phy->attached_sas_addr, SAS_ADDR_SIZE) == 0 && | ||
66 | port->num_phys > 0) { | ||
67 | /* wide port */ | ||
68 | SAS_DPRINTK("phy%d matched wide port%d\n", phy->id, | ||
69 | port->id); | ||
70 | break; | ||
71 | } else if (*(u64 *) port->sas_addr == 0 && port->num_phys==0) { | ||
72 | memcpy(port->sas_addr, phy->sas_addr, SAS_ADDR_SIZE); | ||
73 | break; | ||
74 | } | ||
75 | spin_unlock(&port->phy_list_lock); | ||
76 | } | ||
77 | |||
78 | if (i >= sas_ha->num_phys) { | ||
79 | printk(KERN_NOTICE "%s: couldn't find a free port, bug?\n", | ||
80 | __FUNCTION__); | ||
81 | spin_unlock(&sas_ha->phy_port_lock); | ||
82 | return; | ||
83 | } | ||
84 | |||
85 | /* add the phy to the port */ | ||
86 | list_add_tail(&phy->port_phy_el, &port->phy_list); | ||
87 | phy->port = port; | ||
88 | port->num_phys++; | ||
89 | port->phy_mask |= (1U << phy->id); | ||
90 | |||
91 | if (!port->phy) | ||
92 | port->phy = phy->phy; | ||
93 | |||
94 | SAS_DPRINTK("phy%d added to port%d, phy_mask:0x%x\n", phy->id, | ||
95 | port->id, port->phy_mask); | ||
96 | |||
97 | if (*(u64 *)port->attached_sas_addr == 0) { | ||
98 | port->class = phy->class; | ||
99 | memcpy(port->attached_sas_addr, phy->attached_sas_addr, | ||
100 | SAS_ADDR_SIZE); | ||
101 | port->iproto = phy->iproto; | ||
102 | port->tproto = phy->tproto; | ||
103 | port->oob_mode = phy->oob_mode; | ||
104 | port->linkrate = phy->linkrate; | ||
105 | } else | ||
106 | port->linkrate = max(port->linkrate, phy->linkrate); | ||
107 | spin_unlock(&port->phy_list_lock); | ||
108 | spin_unlock(&sas_ha->phy_port_lock); | ||
109 | |||
110 | if (!port->port) { | ||
111 | port->port = sas_port_alloc(phy->phy->dev.parent, port->id); | ||
112 | BUG_ON(!port->port); | ||
113 | sas_port_add(port->port); | ||
114 | } | ||
115 | sas_port_add_phy(port->port, phy->phy); | ||
116 | |||
117 | if (port->port_dev) | ||
118 | port->port_dev->pathways = port->num_phys; | ||
119 | |||
120 | /* Tell the LLDD about this port formation. */ | ||
121 | if (si->dft->lldd_port_formed) | ||
122 | si->dft->lldd_port_formed(phy); | ||
123 | |||
124 | sas_discover_event(phy->port, DISCE_DISCOVER_DOMAIN); | ||
125 | } | ||
126 | |||
127 | /** | ||
128 | * sas_deform_port -- remove this phy from the port it belongs to | ||
129 | * @phy: the phy of interest | ||
130 | * | ||
131 | * This is called when the physical link to the other phy has been | ||
132 | * lost (on this phy), in Event thread context. We cannot delay here. | ||
133 | */ | ||
134 | void sas_deform_port(struct asd_sas_phy *phy) | ||
135 | { | ||
136 | struct sas_ha_struct *sas_ha = phy->ha; | ||
137 | struct asd_sas_port *port = phy->port; | ||
138 | struct sas_internal *si = | ||
139 | to_sas_internal(sas_ha->core.shost->transportt); | ||
140 | |||
141 | if (!port) | ||
142 | return; /* done by a phy event */ | ||
143 | |||
144 | if (port->port_dev) | ||
145 | port->port_dev->pathways--; | ||
146 | |||
147 | if (port->num_phys == 1) { | ||
148 | sas_unregister_domain_devices(port); | ||
149 | sas_port_delete(port->port); | ||
150 | port->port = NULL; | ||
151 | } else | ||
152 | sas_port_delete_phy(port->port, phy->phy); | ||
153 | |||
154 | |||
155 | if (si->dft->lldd_port_deformed) | ||
156 | si->dft->lldd_port_deformed(phy); | ||
157 | |||
158 | spin_lock(&sas_ha->phy_port_lock); | ||
159 | spin_lock(&port->phy_list_lock); | ||
160 | |||
161 | list_del_init(&phy->port_phy_el); | ||
162 | phy->port = NULL; | ||
163 | port->num_phys--; | ||
164 | port->phy_mask &= ~(1U << phy->id); | ||
165 | |||
166 | if (port->num_phys == 0) { | ||
167 | INIT_LIST_HEAD(&port->phy_list); | ||
168 | memset(port->sas_addr, 0, SAS_ADDR_SIZE); | ||
169 | memset(port->attached_sas_addr, 0, SAS_ADDR_SIZE); | ||
170 | port->class = 0; | ||
171 | port->iproto = 0; | ||
172 | port->tproto = 0; | ||
173 | port->oob_mode = 0; | ||
174 | port->phy_mask = 0; | ||
175 | } | ||
176 | spin_unlock(&port->phy_list_lock); | ||
177 | spin_unlock(&sas_ha->phy_port_lock); | ||
178 | |||
179 | return; | ||
180 | } | ||
181 | |||
182 | /* ---------- SAS port events ---------- */ | ||
183 | |||
184 | void sas_porte_bytes_dmaed(void *data) | ||
185 | { | ||
186 | struct asd_sas_phy *phy = data; | ||
187 | |||
188 | sas_begin_event(PORTE_BYTES_DMAED, &phy->ha->event_lock, | ||
189 | &phy->port_events_pending); | ||
190 | |||
191 | sas_form_port(phy); | ||
192 | } | ||
193 | |||
194 | void sas_porte_broadcast_rcvd(void *data) | ||
195 | { | ||
196 | unsigned long flags; | ||
197 | u32 prim; | ||
198 | struct asd_sas_phy *phy = data; | ||
199 | |||
200 | sas_begin_event(PORTE_BROADCAST_RCVD, &phy->ha->event_lock, | ||
201 | &phy->port_events_pending); | ||
202 | |||
203 | spin_lock_irqsave(&phy->sas_prim_lock, flags); | ||
204 | prim = phy->sas_prim; | ||
205 | spin_unlock_irqrestore(&phy->sas_prim_lock, flags); | ||
206 | |||
207 | SAS_DPRINTK("broadcast received: %d\n", prim); | ||
208 | sas_discover_event(phy->port, DISCE_REVALIDATE_DOMAIN); | ||
209 | } | ||
210 | |||
211 | void sas_porte_link_reset_err(void *data) | ||
212 | { | ||
213 | struct asd_sas_phy *phy = data; | ||
214 | |||
215 | sas_begin_event(PORTE_LINK_RESET_ERR, &phy->ha->event_lock, | ||
216 | &phy->port_events_pending); | ||
217 | |||
218 | sas_deform_port(phy); | ||
219 | } | ||
220 | |||
221 | void sas_porte_timer_event(void *data) | ||
222 | { | ||
223 | struct asd_sas_phy *phy = data; | ||
224 | |||
225 | sas_begin_event(PORTE_TIMER_EVENT, &phy->ha->event_lock, | ||
226 | &phy->port_events_pending); | ||
227 | |||
228 | sas_deform_port(phy); | ||
229 | } | ||
230 | |||
231 | void sas_porte_hard_reset(void *data) | ||
232 | { | ||
233 | struct asd_sas_phy *phy = data; | ||
234 | |||
235 | sas_begin_event(PORTE_HARD_RESET, &phy->ha->event_lock, | ||
236 | &phy->port_events_pending); | ||
237 | |||
238 | sas_deform_port(phy); | ||
239 | } | ||
240 | |||
241 | /* ---------- SAS port registration ---------- */ | ||
242 | |||
243 | static void sas_init_port(struct asd_sas_port *port, | ||
244 | struct sas_ha_struct *sas_ha, int i) | ||
245 | { | ||
246 | port->id = i; | ||
247 | INIT_LIST_HEAD(&port->dev_list); | ||
248 | spin_lock_init(&port->phy_list_lock); | ||
249 | INIT_LIST_HEAD(&port->phy_list); | ||
250 | port->num_phys = 0; | ||
251 | port->phy_mask = 0; | ||
252 | port->ha = sas_ha; | ||
253 | |||
254 | spin_lock_init(&port->dev_list_lock); | ||
255 | } | ||
256 | |||
257 | int sas_register_ports(struct sas_ha_struct *sas_ha) | ||
258 | { | ||
259 | int i; | ||
260 | |||
261 | /* initialize the ports and discovery */ | ||
262 | for (i = 0; i < sas_ha->num_phys; i++) { | ||
263 | struct asd_sas_port *port = sas_ha->sas_port[i]; | ||
264 | |||
265 | sas_init_port(port, sas_ha, i); | ||
266 | sas_init_disc(&port->disc, port); | ||
267 | } | ||
268 | return 0; | ||
269 | } | ||
270 | |||
271 | void sas_unregister_ports(struct sas_ha_struct *sas_ha) | ||
272 | { | ||
273 | int i; | ||
274 | |||
275 | for (i = 0; i < sas_ha->num_phys; i++) | ||
276 | if (sas_ha->sas_phy[i]->port) | ||
277 | sas_deform_port(sas_ha->sas_phy[i]); | ||
278 | |||
279 | } | ||
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c new file mode 100644 index 000000000000..43e0e4e36934 --- /dev/null +++ b/drivers/scsi/libsas/sas_scsi_host.c | |||
@@ -0,0 +1,786 @@ | |||
1 | /* | ||
2 | * Serial Attached SCSI (SAS) class SCSI Host glue. | ||
3 | * | ||
4 | * Copyright (C) 2005 Adaptec, Inc. All rights reserved. | ||
5 | * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> | ||
6 | * | ||
7 | * This file is licensed under GPLv2. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License as | ||
11 | * published by the Free Software Foundation; either version 2 of the | ||
12 | * License, or (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, but | ||
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
17 | * General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | ||
22 | * USA | ||
23 | * | ||
24 | */ | ||
25 | |||
26 | #include "sas_internal.h" | ||
27 | |||
28 | #include <scsi/scsi_host.h> | ||
29 | #include <scsi/scsi_device.h> | ||
30 | #include <scsi/scsi_tcq.h> | ||
31 | #include <scsi/scsi.h> | ||
32 | #include <scsi/scsi_transport.h> | ||
33 | #include <scsi/scsi_transport_sas.h> | ||
34 | #include "../scsi_sas_internal.h" | ||
35 | |||
36 | #include <linux/err.h> | ||
37 | #include <linux/blkdev.h> | ||
38 | #include <linux/scatterlist.h> | ||
39 | |||
40 | /* ---------- SCSI Host glue ---------- */ | ||
41 | |||
42 | #define TO_SAS_TASK(_scsi_cmd) ((void *)(_scsi_cmd)->host_scribble) | ||
43 | #define ASSIGN_SAS_TASK(_sc, _t) do { (_sc)->host_scribble = (void *) _t; } while (0) | ||
44 | |||
45 | static void sas_scsi_task_done(struct sas_task *task) | ||
46 | { | ||
47 | struct task_status_struct *ts = &task->task_status; | ||
48 | struct scsi_cmnd *sc = task->uldd_task; | ||
49 | unsigned ts_flags = task->task_state_flags; | ||
50 | int hs = 0, stat = 0; | ||
51 | |||
52 | if (unlikely(!sc)) { | ||
53 | SAS_DPRINTK("task_done called with non existing SCSI cmnd!\n"); | ||
54 | list_del_init(&task->list); | ||
55 | sas_free_task(task); | ||
56 | return; | ||
57 | } | ||
58 | |||
59 | if (ts->resp == SAS_TASK_UNDELIVERED) { | ||
60 | /* transport error */ | ||
61 | hs = DID_NO_CONNECT; | ||
62 | } else { /* ts->resp == SAS_TASK_COMPLETE */ | ||
63 | /* task delivered, what happened afterwards? */ | ||
64 | switch (ts->stat) { | ||
65 | case SAS_DEV_NO_RESPONSE: | ||
66 | case SAS_INTERRUPTED: | ||
67 | case SAS_PHY_DOWN: | ||
68 | case SAS_NAK_R_ERR: | ||
69 | case SAS_OPEN_TO: | ||
70 | hs = DID_NO_CONNECT; | ||
71 | break; | ||
72 | case SAS_DATA_UNDERRUN: | ||
73 | sc->resid = ts->residual; | ||
74 | if (sc->request_bufflen - sc->resid < sc->underflow) | ||
75 | hs = DID_ERROR; | ||
76 | break; | ||
77 | case SAS_DATA_OVERRUN: | ||
78 | hs = DID_ERROR; | ||
79 | break; | ||
80 | case SAS_QUEUE_FULL: | ||
81 | hs = DID_SOFT_ERROR; /* retry */ | ||
82 | break; | ||
83 | case SAS_DEVICE_UNKNOWN: | ||
84 | hs = DID_BAD_TARGET; | ||
85 | break; | ||
86 | case SAS_SG_ERR: | ||
87 | hs = DID_PARITY; | ||
88 | break; | ||
89 | case SAS_OPEN_REJECT: | ||
90 | if (ts->open_rej_reason == SAS_OREJ_RSVD_RETRY) | ||
91 | hs = DID_SOFT_ERROR; /* retry */ | ||
92 | else | ||
93 | hs = DID_ERROR; | ||
94 | break; | ||
95 | case SAS_PROTO_RESPONSE: | ||
96 | SAS_DPRINTK("LLDD:%s sent SAS_PROTO_RESP for an SSP " | ||
97 | "task; please report this\n", | ||
98 | task->dev->port->ha->sas_ha_name); | ||
99 | break; | ||
100 | case SAS_ABORTED_TASK: | ||
101 | hs = DID_ABORT; | ||
102 | break; | ||
103 | case SAM_CHECK_COND: | ||
104 | memcpy(sc->sense_buffer, ts->buf, | ||
105 | max(SCSI_SENSE_BUFFERSIZE, ts->buf_valid_size)); | ||
106 | stat = SAM_CHECK_COND; | ||
107 | break; | ||
108 | default: | ||
109 | stat = ts->stat; | ||
110 | break; | ||
111 | } | ||
112 | } | ||
113 | ASSIGN_SAS_TASK(sc, NULL); | ||
114 | sc->result = (hs << 16) | stat; | ||
115 | list_del_init(&task->list); | ||
116 | sas_free_task(task); | ||
117 | /* This is very ugly but this is how SCSI Core works. */ | ||
118 | if (ts_flags & SAS_TASK_STATE_ABORTED) | ||
119 | scsi_finish_command(sc); | ||
120 | else | ||
121 | sc->scsi_done(sc); | ||
122 | } | ||
123 | |||
124 | static enum task_attribute sas_scsi_get_task_attr(struct scsi_cmnd *cmd) | ||
125 | { | ||
126 | enum task_attribute ta = TASK_ATTR_SIMPLE; | ||
127 | if (cmd->request && blk_rq_tagged(cmd->request)) { | ||
128 | if (cmd->device->ordered_tags && | ||
129 | (cmd->request->flags & REQ_HARDBARRIER)) | ||
130 | ta = TASK_ATTR_HOQ; | ||
131 | } | ||
132 | return ta; | ||
133 | } | ||
134 | |||
135 | static struct sas_task *sas_create_task(struct scsi_cmnd *cmd, | ||
136 | struct domain_device *dev, | ||
137 | unsigned long gfp_flags) | ||
138 | { | ||
139 | struct sas_task *task = sas_alloc_task(gfp_flags); | ||
140 | struct scsi_lun lun; | ||
141 | |||
142 | if (!task) | ||
143 | return NULL; | ||
144 | |||
145 | *(u32 *)cmd->sense_buffer = 0; | ||
146 | task->uldd_task = cmd; | ||
147 | ASSIGN_SAS_TASK(cmd, task); | ||
148 | |||
149 | task->dev = dev; | ||
150 | task->task_proto = task->dev->tproto; /* BUG_ON(!SSP) */ | ||
151 | |||
152 | task->ssp_task.retry_count = 1; | ||
153 | int_to_scsilun(cmd->device->lun, &lun); | ||
154 | memcpy(task->ssp_task.LUN, &lun.scsi_lun, 8); | ||
155 | task->ssp_task.task_attr = sas_scsi_get_task_attr(cmd); | ||
156 | memcpy(task->ssp_task.cdb, cmd->cmnd, 16); | ||
157 | |||
158 | task->scatter = cmd->request_buffer; | ||
159 | task->num_scatter = cmd->use_sg; | ||
160 | task->total_xfer_len = cmd->request_bufflen; | ||
161 | task->data_dir = cmd->sc_data_direction; | ||
162 | |||
163 | task->task_done = sas_scsi_task_done; | ||
164 | |||
165 | return task; | ||
166 | } | ||
167 | |||
168 | static int sas_queue_up(struct sas_task *task) | ||
169 | { | ||
170 | struct sas_ha_struct *sas_ha = task->dev->port->ha; | ||
171 | struct scsi_core *core = &sas_ha->core; | ||
172 | unsigned long flags; | ||
173 | LIST_HEAD(list); | ||
174 | |||
175 | spin_lock_irqsave(&core->task_queue_lock, flags); | ||
176 | if (sas_ha->lldd_queue_size < core->task_queue_size + 1) { | ||
177 | spin_unlock_irqrestore(&core->task_queue_lock, flags); | ||
178 | return -SAS_QUEUE_FULL; | ||
179 | } | ||
180 | list_add_tail(&task->list, &core->task_queue); | ||
181 | core->task_queue_size += 1; | ||
182 | spin_unlock_irqrestore(&core->task_queue_lock, flags); | ||
183 | up(&core->queue_thread_sema); | ||
184 | |||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | /** | ||
189 | * sas_queuecommand -- Enqueue a command for processing | ||
190 | * @parameters: See SCSI Core documentation | ||
191 | * | ||
192 | * Note: XXX: Remove the host unlock/lock pair when SCSI Core can | ||
193 | * call us without holding an IRQ spinlock... | ||
194 | */ | ||
195 | int sas_queuecommand(struct scsi_cmnd *cmd, | ||
196 | void (*scsi_done)(struct scsi_cmnd *)) | ||
197 | { | ||
198 | int res = 0; | ||
199 | struct domain_device *dev = cmd_to_domain_dev(cmd); | ||
200 | struct Scsi_Host *host = cmd->device->host; | ||
201 | struct sas_internal *i = to_sas_internal(host->transportt); | ||
202 | |||
203 | spin_unlock_irq(host->host_lock); | ||
204 | |||
205 | { | ||
206 | struct sas_ha_struct *sas_ha = dev->port->ha; | ||
207 | struct sas_task *task; | ||
208 | |||
209 | res = -ENOMEM; | ||
210 | task = sas_create_task(cmd, dev, GFP_ATOMIC); | ||
211 | if (!task) | ||
212 | goto out; | ||
213 | |||
214 | cmd->scsi_done = scsi_done; | ||
215 | /* Queue up, Direct Mode or Task Collector Mode. */ | ||
216 | if (sas_ha->lldd_max_execute_num < 2) | ||
217 | res = i->dft->lldd_execute_task(task, 1, GFP_ATOMIC); | ||
218 | else | ||
219 | res = sas_queue_up(task); | ||
220 | |||
221 | /* Examine */ | ||
222 | if (res) { | ||
223 | SAS_DPRINTK("lldd_execute_task returned: %d\n", res); | ||
224 | ASSIGN_SAS_TASK(cmd, NULL); | ||
225 | sas_free_task(task); | ||
226 | if (res == -SAS_QUEUE_FULL) { | ||
227 | cmd->result = DID_SOFT_ERROR << 16; /* retry */ | ||
228 | res = 0; | ||
229 | scsi_done(cmd); | ||
230 | } | ||
231 | goto out; | ||
232 | } | ||
233 | } | ||
234 | out: | ||
235 | spin_lock_irq(host->host_lock); | ||
236 | return res; | ||
237 | } | ||
238 | |||
239 | static void sas_scsi_clear_queue_lu(struct list_head *error_q, struct scsi_cmnd *my_cmd) | ||
240 | { | ||
241 | struct scsi_cmnd *cmd, *n; | ||
242 | |||
243 | list_for_each_entry_safe(cmd, n, error_q, eh_entry) { | ||
244 | if (cmd == my_cmd) | ||
245 | list_del_init(&cmd->eh_entry); | ||
246 | } | ||
247 | } | ||
248 | |||
249 | static void sas_scsi_clear_queue_I_T(struct list_head *error_q, | ||
250 | struct domain_device *dev) | ||
251 | { | ||
252 | struct scsi_cmnd *cmd, *n; | ||
253 | |||
254 | list_for_each_entry_safe(cmd, n, error_q, eh_entry) { | ||
255 | struct domain_device *x = cmd_to_domain_dev(cmd); | ||
256 | |||
257 | if (x == dev) | ||
258 | list_del_init(&cmd->eh_entry); | ||
259 | } | ||
260 | } | ||
261 | |||
262 | static void sas_scsi_clear_queue_port(struct list_head *error_q, | ||
263 | struct asd_sas_port *port) | ||
264 | { | ||
265 | struct scsi_cmnd *cmd, *n; | ||
266 | |||
267 | list_for_each_entry_safe(cmd, n, error_q, eh_entry) { | ||
268 | struct domain_device *dev = cmd_to_domain_dev(cmd); | ||
269 | struct asd_sas_port *x = dev->port; | ||
270 | |||
271 | if (x == port) | ||
272 | list_del_init(&cmd->eh_entry); | ||
273 | } | ||
274 | } | ||
275 | |||
276 | enum task_disposition { | ||
277 | TASK_IS_DONE, | ||
278 | TASK_IS_ABORTED, | ||
279 | TASK_IS_AT_LU, | ||
280 | TASK_IS_NOT_AT_LU, | ||
281 | }; | ||
282 | |||
283 | static enum task_disposition sas_scsi_find_task(struct sas_task *task) | ||
284 | { | ||
285 | struct sas_ha_struct *ha = task->dev->port->ha; | ||
286 | unsigned long flags; | ||
287 | int i, res; | ||
288 | struct sas_internal *si = | ||
289 | to_sas_internal(task->dev->port->ha->core.shost->transportt); | ||
290 | |||
291 | if (ha->lldd_max_execute_num > 1) { | ||
292 | struct scsi_core *core = &ha->core; | ||
293 | struct sas_task *t, *n; | ||
294 | |||
295 | spin_lock_irqsave(&core->task_queue_lock, flags); | ||
296 | list_for_each_entry_safe(t, n, &core->task_queue, list) { | ||
297 | if (task == t) { | ||
298 | list_del_init(&t->list); | ||
299 | spin_unlock_irqrestore(&core->task_queue_lock, | ||
300 | flags); | ||
301 | SAS_DPRINTK("%s: task 0x%p aborted from " | ||
302 | "task_queue\n", | ||
303 | __FUNCTION__, task); | ||
304 | return TASK_IS_ABORTED; | ||
305 | } | ||
306 | } | ||
307 | spin_unlock_irqrestore(&core->task_queue_lock, flags); | ||
308 | } | ||
309 | |||
310 | for (i = 0; i < 5; i++) { | ||
311 | SAS_DPRINTK("%s: aborting task 0x%p\n", __FUNCTION__, task); | ||
312 | res = si->dft->lldd_abort_task(task); | ||
313 | |||
314 | spin_lock_irqsave(&task->task_state_lock, flags); | ||
315 | if (task->task_state_flags & SAS_TASK_STATE_DONE) { | ||
316 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
317 | SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__, | ||
318 | task); | ||
319 | return TASK_IS_DONE; | ||
320 | } | ||
321 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
322 | |||
323 | if (res == TMF_RESP_FUNC_COMPLETE) { | ||
324 | SAS_DPRINTK("%s: task 0x%p is aborted\n", | ||
325 | __FUNCTION__, task); | ||
326 | return TASK_IS_ABORTED; | ||
327 | } else if (si->dft->lldd_query_task) { | ||
328 | SAS_DPRINTK("%s: querying task 0x%p\n", | ||
329 | __FUNCTION__, task); | ||
330 | res = si->dft->lldd_query_task(task); | ||
331 | if (res == TMF_RESP_FUNC_SUCC) { | ||
332 | SAS_DPRINTK("%s: task 0x%p at LU\n", | ||
333 | __FUNCTION__, task); | ||
334 | return TASK_IS_AT_LU; | ||
335 | } else if (res == TMF_RESP_FUNC_COMPLETE) { | ||
336 | SAS_DPRINTK("%s: task 0x%p not at LU\n", | ||
337 | __FUNCTION__, task); | ||
338 | return TASK_IS_NOT_AT_LU; | ||
339 | } | ||
340 | } | ||
341 | } | ||
342 | return res; | ||
343 | } | ||
344 | |||
345 | static int sas_recover_lu(struct domain_device *dev, struct scsi_cmnd *cmd) | ||
346 | { | ||
347 | int res = TMF_RESP_FUNC_FAILED; | ||
348 | struct scsi_lun lun; | ||
349 | struct sas_internal *i = | ||
350 | to_sas_internal(dev->port->ha->core.shost->transportt); | ||
351 | |||
352 | int_to_scsilun(cmd->device->lun, &lun); | ||
353 | |||
354 | SAS_DPRINTK("eh: device %llx LUN %x has the task\n", | ||
355 | SAS_ADDR(dev->sas_addr), | ||
356 | cmd->device->lun); | ||
357 | |||
358 | if (i->dft->lldd_abort_task_set) | ||
359 | res = i->dft->lldd_abort_task_set(dev, lun.scsi_lun); | ||
360 | |||
361 | if (res == TMF_RESP_FUNC_FAILED) { | ||
362 | if (i->dft->lldd_clear_task_set) | ||
363 | res = i->dft->lldd_clear_task_set(dev, lun.scsi_lun); | ||
364 | } | ||
365 | |||
366 | if (res == TMF_RESP_FUNC_FAILED) { | ||
367 | if (i->dft->lldd_lu_reset) | ||
368 | res = i->dft->lldd_lu_reset(dev, lun.scsi_lun); | ||
369 | } | ||
370 | |||
371 | return res; | ||
372 | } | ||
373 | |||
374 | static int sas_recover_I_T(struct domain_device *dev) | ||
375 | { | ||
376 | int res = TMF_RESP_FUNC_FAILED; | ||
377 | struct sas_internal *i = | ||
378 | to_sas_internal(dev->port->ha->core.shost->transportt); | ||
379 | |||
380 | SAS_DPRINTK("I_T nexus reset for dev %016llx\n", | ||
381 | SAS_ADDR(dev->sas_addr)); | ||
382 | |||
383 | if (i->dft->lldd_I_T_nexus_reset) | ||
384 | res = i->dft->lldd_I_T_nexus_reset(dev); | ||
385 | |||
386 | return res; | ||
387 | } | ||
388 | |||
389 | void sas_scsi_recover_host(struct Scsi_Host *shost) | ||
390 | { | ||
391 | struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost); | ||
392 | unsigned long flags; | ||
393 | LIST_HEAD(error_q); | ||
394 | struct scsi_cmnd *cmd, *n; | ||
395 | enum task_disposition res = TASK_IS_DONE; | ||
396 | int tmf_resp; | ||
397 | struct sas_internal *i = to_sas_internal(shost->transportt); | ||
398 | |||
399 | spin_lock_irqsave(shost->host_lock, flags); | ||
400 | list_splice_init(&shost->eh_cmd_q, &error_q); | ||
401 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
402 | |||
403 | SAS_DPRINTK("Enter %s\n", __FUNCTION__); | ||
404 | |||
405 | /* All tasks on this list were marked SAS_TASK_STATE_ABORTED | ||
406 | * by sas_scsi_timed_out() callback. | ||
407 | */ | ||
408 | Again: | ||
409 | SAS_DPRINTK("going over list...\n"); | ||
410 | list_for_each_entry_safe(cmd, n, &error_q, eh_entry) { | ||
411 | struct sas_task *task = TO_SAS_TASK(cmd); | ||
412 | |||
413 | SAS_DPRINTK("trying to find task 0x%p\n", task); | ||
414 | list_del_init(&cmd->eh_entry); | ||
415 | res = sas_scsi_find_task(task); | ||
416 | |||
417 | cmd->eh_eflags = 0; | ||
418 | shost->host_failed--; | ||
419 | |||
420 | switch (res) { | ||
421 | case TASK_IS_DONE: | ||
422 | SAS_DPRINTK("%s: task 0x%p is done\n", __FUNCTION__, | ||
423 | task); | ||
424 | task->task_done(task); | ||
425 | continue; | ||
426 | case TASK_IS_ABORTED: | ||
427 | SAS_DPRINTK("%s: task 0x%p is aborted\n", | ||
428 | __FUNCTION__, task); | ||
429 | task->task_done(task); | ||
430 | continue; | ||
431 | case TASK_IS_AT_LU: | ||
432 | SAS_DPRINTK("task 0x%p is at LU: lu recover\n", task); | ||
433 | tmf_resp = sas_recover_lu(task->dev, cmd); | ||
434 | if (tmf_resp == TMF_RESP_FUNC_COMPLETE) { | ||
435 | SAS_DPRINTK("dev %016llx LU %x is " | ||
436 | "recovered\n", | ||
437 | SAS_ADDR(task->dev), | ||
438 | cmd->device->lun); | ||
439 | task->task_done(task); | ||
440 | sas_scsi_clear_queue_lu(&error_q, cmd); | ||
441 | goto Again; | ||
442 | } | ||
443 | /* fallthrough */ | ||
444 | case TASK_IS_NOT_AT_LU: | ||
445 | SAS_DPRINTK("task 0x%p is not at LU: I_T recover\n", | ||
446 | task); | ||
447 | tmf_resp = sas_recover_I_T(task->dev); | ||
448 | if (tmf_resp == TMF_RESP_FUNC_COMPLETE) { | ||
449 | SAS_DPRINTK("I_T %016llx recovered\n", | ||
450 | SAS_ADDR(task->dev->sas_addr)); | ||
451 | task->task_done(task); | ||
452 | sas_scsi_clear_queue_I_T(&error_q, task->dev); | ||
453 | goto Again; | ||
454 | } | ||
455 | /* Hammer time :-) */ | ||
456 | if (i->dft->lldd_clear_nexus_port) { | ||
457 | struct asd_sas_port *port = task->dev->port; | ||
458 | SAS_DPRINTK("clearing nexus for port:%d\n", | ||
459 | port->id); | ||
460 | res = i->dft->lldd_clear_nexus_port(port); | ||
461 | if (res == TMF_RESP_FUNC_COMPLETE) { | ||
462 | SAS_DPRINTK("clear nexus port:%d " | ||
463 | "succeeded\n", port->id); | ||
464 | task->task_done(task); | ||
465 | sas_scsi_clear_queue_port(&error_q, | ||
466 | port); | ||
467 | goto Again; | ||
468 | } | ||
469 | } | ||
470 | if (i->dft->lldd_clear_nexus_ha) { | ||
471 | SAS_DPRINTK("clear nexus ha\n"); | ||
472 | res = i->dft->lldd_clear_nexus_ha(ha); | ||
473 | if (res == TMF_RESP_FUNC_COMPLETE) { | ||
474 | SAS_DPRINTK("clear nexus ha " | ||
475 | "succeeded\n"); | ||
476 | task->task_done(task); | ||
477 | goto out; | ||
478 | } | ||
479 | } | ||
480 | /* If we are here -- this means that no amount | ||
481 | * of effort could recover from errors. Quite | ||
482 | * possibly the HA just disappeared. | ||
483 | */ | ||
484 | SAS_DPRINTK("error from device %llx, LUN %x " | ||
485 | "couldn't be recovered in any way\n", | ||
486 | SAS_ADDR(task->dev->sas_addr), | ||
487 | cmd->device->lun); | ||
488 | |||
489 | task->task_done(task); | ||
490 | goto clear_q; | ||
491 | } | ||
492 | } | ||
493 | out: | ||
494 | SAS_DPRINTK("--- Exit %s\n", __FUNCTION__); | ||
495 | return; | ||
496 | clear_q: | ||
497 | SAS_DPRINTK("--- Exit %s -- clear_q\n", __FUNCTION__); | ||
498 | list_for_each_entry_safe(cmd, n, &error_q, eh_entry) { | ||
499 | struct sas_task *task = TO_SAS_TASK(cmd); | ||
500 | list_del_init(&cmd->eh_entry); | ||
501 | task->task_done(task); | ||
502 | } | ||
503 | } | ||
504 | |||
505 | enum scsi_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *cmd) | ||
506 | { | ||
507 | struct sas_task *task = TO_SAS_TASK(cmd); | ||
508 | unsigned long flags; | ||
509 | |||
510 | if (!task) { | ||
511 | SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_HANDLED\n", | ||
512 | cmd, task); | ||
513 | return EH_HANDLED; | ||
514 | } | ||
515 | |||
516 | spin_lock_irqsave(&task->task_state_lock, flags); | ||
517 | if (task->task_state_flags & SAS_TASK_STATE_DONE) { | ||
518 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
519 | SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_HANDLED\n", | ||
520 | cmd, task); | ||
521 | return EH_HANDLED; | ||
522 | } | ||
523 | task->task_state_flags |= SAS_TASK_STATE_ABORTED; | ||
524 | spin_unlock_irqrestore(&task->task_state_lock, flags); | ||
525 | |||
526 | SAS_DPRINTK("command 0x%p, task 0x%p, timed out: EH_NOT_HANDLED\n", | ||
527 | cmd, task); | ||
528 | |||
529 | return EH_NOT_HANDLED; | ||
530 | } | ||
531 | |||
532 | struct domain_device *sas_find_dev_by_rphy(struct sas_rphy *rphy) | ||
533 | { | ||
534 | struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent); | ||
535 | struct sas_ha_struct *ha = SHOST_TO_SAS_HA(shost); | ||
536 | struct domain_device *found_dev = NULL; | ||
537 | int i; | ||
538 | |||
539 | spin_lock(&ha->phy_port_lock); | ||
540 | for (i = 0; i < ha->num_phys; i++) { | ||
541 | struct asd_sas_port *port = ha->sas_port[i]; | ||
542 | struct domain_device *dev; | ||
543 | |||
544 | spin_lock(&port->dev_list_lock); | ||
545 | list_for_each_entry(dev, &port->dev_list, dev_list_node) { | ||
546 | if (rphy == dev->rphy) { | ||
547 | found_dev = dev; | ||
548 | spin_unlock(&port->dev_list_lock); | ||
549 | goto found; | ||
550 | } | ||
551 | } | ||
552 | spin_unlock(&port->dev_list_lock); | ||
553 | } | ||
554 | found: | ||
555 | spin_unlock(&ha->phy_port_lock); | ||
556 | |||
557 | return found_dev; | ||
558 | } | ||
559 | |||
560 | static inline struct domain_device *sas_find_target(struct scsi_target *starget) | ||
561 | { | ||
562 | struct sas_rphy *rphy = dev_to_rphy(starget->dev.parent); | ||
563 | |||
564 | return sas_find_dev_by_rphy(rphy); | ||
565 | } | ||
566 | |||
567 | int sas_target_alloc(struct scsi_target *starget) | ||
568 | { | ||
569 | struct domain_device *found_dev = sas_find_target(starget); | ||
570 | |||
571 | if (!found_dev) | ||
572 | return -ENODEV; | ||
573 | |||
574 | starget->hostdata = found_dev; | ||
575 | return 0; | ||
576 | } | ||
577 | |||
578 | #define SAS_DEF_QD 32 | ||
579 | #define SAS_MAX_QD 64 | ||
580 | |||
581 | int sas_slave_configure(struct scsi_device *scsi_dev) | ||
582 | { | ||
583 | struct domain_device *dev = sdev_to_domain_dev(scsi_dev); | ||
584 | struct sas_ha_struct *sas_ha; | ||
585 | |||
586 | BUG_ON(dev->rphy->identify.device_type != SAS_END_DEVICE); | ||
587 | |||
588 | sas_ha = dev->port->ha; | ||
589 | |||
590 | sas_read_port_mode_page(scsi_dev); | ||
591 | |||
592 | if (scsi_dev->tagged_supported) { | ||
593 | scsi_set_tag_type(scsi_dev, MSG_SIMPLE_TAG); | ||
594 | scsi_activate_tcq(scsi_dev, SAS_DEF_QD); | ||
595 | } else { | ||
596 | SAS_DPRINTK("device %llx, LUN %x doesn't support " | ||
597 | "TCQ\n", SAS_ADDR(dev->sas_addr), | ||
598 | scsi_dev->lun); | ||
599 | scsi_dev->tagged_supported = 0; | ||
600 | scsi_set_tag_type(scsi_dev, 0); | ||
601 | scsi_deactivate_tcq(scsi_dev, 1); | ||
602 | } | ||
603 | |||
604 | return 0; | ||
605 | } | ||
606 | |||
607 | void sas_slave_destroy(struct scsi_device *scsi_dev) | ||
608 | { | ||
609 | } | ||
610 | |||
611 | int sas_change_queue_depth(struct scsi_device *scsi_dev, int new_depth) | ||
612 | { | ||
613 | int res = min(new_depth, SAS_MAX_QD); | ||
614 | |||
615 | if (scsi_dev->tagged_supported) | ||
616 | scsi_adjust_queue_depth(scsi_dev, scsi_get_tag_type(scsi_dev), | ||
617 | res); | ||
618 | else { | ||
619 | struct domain_device *dev = sdev_to_domain_dev(scsi_dev); | ||
620 | sas_printk("device %llx LUN %x queue depth changed to 1\n", | ||
621 | SAS_ADDR(dev->sas_addr), | ||
622 | scsi_dev->lun); | ||
623 | scsi_adjust_queue_depth(scsi_dev, 0, 1); | ||
624 | res = 1; | ||
625 | } | ||
626 | |||
627 | return res; | ||
628 | } | ||
629 | |||
630 | int sas_change_queue_type(struct scsi_device *scsi_dev, int qt) | ||
631 | { | ||
632 | if (!scsi_dev->tagged_supported) | ||
633 | return 0; | ||
634 | |||
635 | scsi_deactivate_tcq(scsi_dev, 1); | ||
636 | |||
637 | scsi_set_tag_type(scsi_dev, qt); | ||
638 | scsi_activate_tcq(scsi_dev, scsi_dev->queue_depth); | ||
639 | |||
640 | return qt; | ||
641 | } | ||
642 | |||
643 | int sas_bios_param(struct scsi_device *scsi_dev, | ||
644 | struct block_device *bdev, | ||
645 | sector_t capacity, int *hsc) | ||
646 | { | ||
647 | hsc[0] = 255; | ||
648 | hsc[1] = 63; | ||
649 | sector_div(capacity, 255*63); | ||
650 | hsc[2] = capacity; | ||
651 | |||
652 | return 0; | ||
653 | } | ||
654 | |||
655 | /* ---------- Task Collector Thread implementation ---------- */ | ||
656 | |||
657 | static void sas_queue(struct sas_ha_struct *sas_ha) | ||
658 | { | ||
659 | struct scsi_core *core = &sas_ha->core; | ||
660 | unsigned long flags; | ||
661 | LIST_HEAD(q); | ||
662 | int can_queue; | ||
663 | int res; | ||
664 | struct sas_internal *i = to_sas_internal(core->shost->transportt); | ||
665 | |||
666 | spin_lock_irqsave(&core->task_queue_lock, flags); | ||
667 | while (!core->queue_thread_kill && | ||
668 | !list_empty(&core->task_queue)) { | ||
669 | |||
670 | can_queue = sas_ha->lldd_queue_size - core->task_queue_size; | ||
671 | if (can_queue >= 0) { | ||
672 | can_queue = core->task_queue_size; | ||
673 | list_splice_init(&core->task_queue, &q); | ||
674 | } else { | ||
675 | struct list_head *a, *n; | ||
676 | |||
677 | can_queue = sas_ha->lldd_queue_size; | ||
678 | list_for_each_safe(a, n, &core->task_queue) { | ||
679 | list_move_tail(a, &q); | ||
680 | if (--can_queue == 0) | ||
681 | break; | ||
682 | } | ||
683 | can_queue = sas_ha->lldd_queue_size; | ||
684 | } | ||
685 | core->task_queue_size -= can_queue; | ||
686 | spin_unlock_irqrestore(&core->task_queue_lock, flags); | ||
687 | { | ||
688 | struct sas_task *task = list_entry(q.next, | ||
689 | struct sas_task, | ||
690 | list); | ||
691 | list_del_init(&q); | ||
692 | res = i->dft->lldd_execute_task(task, can_queue, | ||
693 | GFP_KERNEL); | ||
694 | if (unlikely(res)) | ||
695 | __list_add(&q, task->list.prev, &task->list); | ||
696 | } | ||
697 | spin_lock_irqsave(&core->task_queue_lock, flags); | ||
698 | if (res) { | ||
699 | list_splice_init(&q, &core->task_queue); /*at head*/ | ||
700 | core->task_queue_size += can_queue; | ||
701 | } | ||
702 | } | ||
703 | spin_unlock_irqrestore(&core->task_queue_lock, flags); | ||
704 | } | ||
705 | |||
706 | static DECLARE_COMPLETION(queue_th_comp); | ||
707 | |||
708 | /** | ||
709 | * sas_queue_thread -- The Task Collector thread | ||
710 | * @_sas_ha: pointer to struct sas_ha | ||
711 | */ | ||
712 | static int sas_queue_thread(void *_sas_ha) | ||
713 | { | ||
714 | struct sas_ha_struct *sas_ha = _sas_ha; | ||
715 | struct scsi_core *core = &sas_ha->core; | ||
716 | |||
717 | daemonize("sas_queue_%d", core->shost->host_no); | ||
718 | current->flags |= PF_NOFREEZE; | ||
719 | |||
720 | complete(&queue_th_comp); | ||
721 | |||
722 | while (1) { | ||
723 | down_interruptible(&core->queue_thread_sema); | ||
724 | sas_queue(sas_ha); | ||
725 | if (core->queue_thread_kill) | ||
726 | break; | ||
727 | } | ||
728 | |||
729 | complete(&queue_th_comp); | ||
730 | |||
731 | return 0; | ||
732 | } | ||
733 | |||
734 | int sas_init_queue(struct sas_ha_struct *sas_ha) | ||
735 | { | ||
736 | int res; | ||
737 | struct scsi_core *core = &sas_ha->core; | ||
738 | |||
739 | spin_lock_init(&core->task_queue_lock); | ||
740 | core->task_queue_size = 0; | ||
741 | INIT_LIST_HEAD(&core->task_queue); | ||
742 | init_MUTEX_LOCKED(&core->queue_thread_sema); | ||
743 | |||
744 | res = kernel_thread(sas_queue_thread, sas_ha, 0); | ||
745 | if (res >= 0) | ||
746 | wait_for_completion(&queue_th_comp); | ||
747 | |||
748 | return res < 0 ? res : 0; | ||
749 | } | ||
750 | |||
751 | void sas_shutdown_queue(struct sas_ha_struct *sas_ha) | ||
752 | { | ||
753 | unsigned long flags; | ||
754 | struct scsi_core *core = &sas_ha->core; | ||
755 | struct sas_task *task, *n; | ||
756 | |||
757 | init_completion(&queue_th_comp); | ||
758 | core->queue_thread_kill = 1; | ||
759 | up(&core->queue_thread_sema); | ||
760 | wait_for_completion(&queue_th_comp); | ||
761 | |||
762 | if (!list_empty(&core->task_queue)) | ||
763 | SAS_DPRINTK("HA: %llx: scsi core task queue is NOT empty!?\n", | ||
764 | SAS_ADDR(sas_ha->sas_addr)); | ||
765 | |||
766 | spin_lock_irqsave(&core->task_queue_lock, flags); | ||
767 | list_for_each_entry_safe(task, n, &core->task_queue, list) { | ||
768 | struct scsi_cmnd *cmd = task->uldd_task; | ||
769 | |||
770 | list_del_init(&task->list); | ||
771 | |||
772 | ASSIGN_SAS_TASK(cmd, NULL); | ||
773 | sas_free_task(task); | ||
774 | cmd->result = DID_ABORT << 16; | ||
775 | cmd->scsi_done(cmd); | ||
776 | } | ||
777 | spin_unlock_irqrestore(&core->task_queue_lock, flags); | ||
778 | } | ||
779 | |||
780 | EXPORT_SYMBOL_GPL(sas_queuecommand); | ||
781 | EXPORT_SYMBOL_GPL(sas_target_alloc); | ||
782 | EXPORT_SYMBOL_GPL(sas_slave_configure); | ||
783 | EXPORT_SYMBOL_GPL(sas_slave_destroy); | ||
784 | EXPORT_SYMBOL_GPL(sas_change_queue_depth); | ||
785 | EXPORT_SYMBOL_GPL(sas_change_queue_type); | ||
786 | EXPORT_SYMBOL_GPL(sas_bios_param); | ||