From 09345f65058bb927f3b3f4c33421f83ba8eeb5f8 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Wed, 27 Jun 2007 16:32:39 +0900 Subject: [SCSI] add srp transport class This adds srp transport class that works with ib_srp and ibmvscsi. It creates only /sys/class/{srp_host,srp_remote_ports} and srp_remote_ports has only "port_id" attribute. viola:/sys/class/srp_remote_ports/port-0:1# ls device port_id subsystem uevent viola:/sys/class/srp_remote_ports/port-0:1# cat port_id 4c:49:4e:55:58:20:56:49:4f:00:00:00:00:00:00:00 Signed-off-by: FUJITA Tomonori Signed-off-by: James Bottomley --- drivers/scsi/Kconfig | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/scsi/Kconfig') diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index d2b3898b750a..50d3062577dc 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -289,6 +289,13 @@ config SCSI_SAS_ATTRS source "drivers/scsi/libsas/Kconfig" +config SCSI_SRP_ATTRS + tristate "SRP Transport Attributes" + depends on SCSI + help + If you wish to export transport-specific information about + each attached SRP device to sysfs, say Y. + endmenu menuconfig SCSI_LOWLEVEL -- cgit v1.2.3 From 4d68041907b150b07640b607c6c626391cf3fe8b Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Wed, 27 Jun 2007 16:32:50 +0900 Subject: [SCSI] ibmvscsi: convert to use the srp transport class This converts ibmvscsi to use the srp transport class. Signed-off-by: FUJITA Tomonori Acked-by: Brian King Signed-off-by: James Bottomley --- drivers/scsi/Kconfig | 1 + drivers/scsi/ibmvscsi/ibmvscsi.c | 34 ++++++++++++++++++++++++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) (limited to 'drivers/scsi/Kconfig') diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 50d3062577dc..778dc0fb1e4f 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -839,6 +839,7 @@ config SCSI_IPS config SCSI_IBMVSCSI tristate "IBM Virtual SCSI support" depends on PPC_PSERIES || PPC_ISERIES + select SCSI_SRP_ATTRS help This is the IBM POWER Virtual SCSI Client diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 5ecc63d1b436..e6f937eeb78f 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -75,6 +75,7 @@ #include #include #include +#include #include "ibmvscsi.h" /* The values below are somewhat arbitrary default values, but @@ -87,6 +88,8 @@ static int max_channel = 3; static int init_timeout = 5; static int max_requests = IBMVSCSI_MAX_REQUESTS_DEFAULT; +static struct scsi_transport_template *ibmvscsi_transport_template; + #define IBMVSCSI_VERSION "1.5.8" MODULE_DESCRIPTION("IBM Virtual SCSI"); @@ -1553,6 +1556,8 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id) struct ibmvscsi_host_data *hostdata; struct Scsi_Host *host; struct device *dev = &vdev->dev; + struct srp_rport_identifiers ids; + struct srp_rport *rport; unsigned long wait_switch = 0; int rc; @@ -1565,6 +1570,7 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id) goto scsi_host_alloc_failed; } + host->transportt = ibmvscsi_transport_template; hostdata = shost_priv(host); memset(hostdata, 0x00, sizeof(*hostdata)); INIT_LIST_HEAD(&hostdata->sent); @@ -1590,6 +1596,13 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id) if (scsi_add_host(hostdata->host, hostdata->dev)) goto add_host_failed; + /* we don't have a proper target_port_id so let's use the fake one */ + memcpy(ids.port_id, hostdata->madapter_info.partition_name, + sizeof(ids.port_id)); + rport = srp_rport_add(host, &ids); + if (IS_ERR(rport)) + goto add_srp_port_failed; + /* Try to send an initialization message. Note that this is allowed * to fail if the other end is not acive. In that case we don't * want to scan @@ -1617,6 +1630,8 @@ static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id) vdev->dev.driver_data = hostdata; return 0; + add_srp_port_failed: + scsi_remove_host(hostdata->host); add_host_failed: release_event_pool(&hostdata->pool, hostdata); init_pool_failed: @@ -1633,7 +1648,8 @@ static int ibmvscsi_remove(struct vio_dev *vdev) release_event_pool(&hostdata->pool, hostdata); ibmvscsi_release_crq_queue(&hostdata->queue, hostdata, max_requests); - + + srp_remove_host(hostdata->host); scsi_remove_host(hostdata->host); scsi_host_put(hostdata->host); @@ -1660,14 +1676,28 @@ static struct vio_driver ibmvscsi_driver = { } }; +static struct srp_function_template ibmvscsi_transport_functions = { +}; + int __init ibmvscsi_module_init(void) { - return vio_register_driver(&ibmvscsi_driver); + int ret; + + ibmvscsi_transport_template = + srp_attach_transport(&ibmvscsi_transport_functions); + if (!ibmvscsi_transport_template) + return -ENOMEM; + + ret = vio_register_driver(&ibmvscsi_driver); + if (ret) + srp_release_transport(ibmvscsi_transport_template); + return ret; } void __exit ibmvscsi_module_exit(void) { vio_unregister_driver(&ibmvscsi_driver); + srp_release_transport(ibmvscsi_transport_template); } module_init(ibmvscsi_module_init); -- cgit v1.2.3 From 62fe88261b9d865264d857777cf58a0335513151 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Wed, 11 Jul 2007 15:08:19 +0900 Subject: [SCSI] srp_transport: add target driver support This adds minimum target driver support: - srp_rport_{add,del} calls scsi_tgt_it_nexus_{create,destroy} for target drivers. - add a callback to notify target drivers of the nexus operation results to srp_function_template. Signed-off-by: FUJITA Tomonori Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/Kconfig | 2 +- drivers/scsi/scsi_transport_srp.c | 24 ++++++++++++++++++++++++ include/scsi/scsi_transport_srp.h | 3 ++- 3 files changed, 27 insertions(+), 2 deletions(-) (limited to 'drivers/scsi/Kconfig') diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 778dc0fb1e4f..8d4057ea27b1 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -291,7 +291,7 @@ source "drivers/scsi/libsas/Kconfig" config SCSI_SRP_ATTRS tristate "SRP Transport Attributes" - depends on SCSI + depends on SCSI && SCSI_TGT help If you wish to export transport-specific information about each attached SRP device to sysfs, say Y. diff --git a/drivers/scsi/scsi_transport_srp.c b/drivers/scsi/scsi_transport_srp.c index 608abd8aef20..8e5b41ca181d 100644 --- a/drivers/scsi/scsi_transport_srp.c +++ b/drivers/scsi/scsi_transport_srp.c @@ -30,6 +30,7 @@ #include #include #include +#include struct srp_host_attrs { atomic_t next_port_id; @@ -221,6 +222,17 @@ struct srp_rport *srp_rport_add(struct Scsi_Host *shost, return ERR_PTR(ret); } + if (ids->roles == SRP_RPORT_ROLE_INITIATOR) { + ret = scsi_tgt_it_nexus_create(shost, (unsigned long)rport, + rport->port_id); + if (ret) { + device_del(&rport->dev); + transport_destroy_device(&rport->dev); + put_device(&rport->dev); + return ERR_PTR(ret); + } + } + transport_add_device(&rport->dev); transport_configure_device(&rport->dev); @@ -238,6 +250,10 @@ void srp_rport_del(struct srp_rport *rport) { struct device *dev = &rport->dev; + if (rport->roles == SRP_RPORT_ROLE_INITIATOR) + scsi_tgt_it_nexus_destroy(dev_to_shost(dev->parent), + (unsigned long)rport); + transport_remove_device(dev); device_del(dev); transport_destroy_device(dev); @@ -264,6 +280,12 @@ void srp_remove_host(struct Scsi_Host *shost) } EXPORT_SYMBOL_GPL(srp_remove_host); +static int srp_it_nexus_response(struct Scsi_Host *shost, u64 id, int result) +{ + struct srp_internal *i = to_srp_internal(shost->transportt); + return i->f->it_nexus_response(shost, id, result); +} + /** * srp_attach_transport -- instantiate SRP transport template * @ft: SRP transport class function template @@ -278,6 +300,8 @@ srp_attach_transport(struct srp_function_template *ft) if (!i) return NULL; + i->t.it_nexus_response = srp_it_nexus_response; + i->t.host_size = sizeof(struct srp_host_attrs); i->t.host_attrs.ac.attrs = &i->host_attrs[0]; i->t.host_attrs.ac.class = &srp_host_class.class; diff --git a/include/scsi/scsi_transport_srp.h b/include/scsi/scsi_transport_srp.h index 08b4a28a77b8..a705dbc016b3 100644 --- a/include/scsi/scsi_transport_srp.h +++ b/include/scsi/scsi_transport_srp.h @@ -21,7 +21,8 @@ struct srp_rport { }; struct srp_function_template { - /* later */ + /* for target drivers */ + int (* it_nexus_response)(struct Scsi_Host *, u64, int); }; extern struct scsi_transport_template * -- cgit v1.2.3 From 17b0bcfad795913b1f2a3926cd238fa2ad5522a2 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Wed, 11 Jul 2007 15:08:21 +0900 Subject: [SCSI] tgt: convert libsrp and ibmvstgt to use srp_transport This converts libsrp and ibmvstgt to use srp transport. Signed-off-by: FUJITA Tomonori Signed-off-by: Mike Christie Acked-by: Brian King Signed-off-by: James Bottomley --- drivers/scsi/Kconfig | 2 +- drivers/scsi/ibmvscsi/ibmvstgt.c | 58 +++++++++++++++++++++++++++++++++++----- drivers/scsi/libsrp.c | 5 ++-- include/scsi/libsrp.h | 2 +- 4 files changed, 57 insertions(+), 10 deletions(-) (limited to 'drivers/scsi/Kconfig') diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 8d4057ea27b1..4562273dfad3 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -848,7 +848,7 @@ config SCSI_IBMVSCSI config SCSI_IBMVSCSIS tristate "IBM Virtual SCSI Server support" - depends on PPC_PSERIES && SCSI_TGT && SCSI_SRP + depends on PPC_PSERIES && SCSI_TGT && SCSI_SRP && SCSI_SRP_ATTRS help This is the SRP target driver for IBM pSeries virtual environments. diff --git a/drivers/scsi/ibmvscsi/ibmvstgt.c b/drivers/scsi/ibmvscsi/ibmvstgt.c index 8ba7dd09d01d..4ee6e417d0bf 100644 --- a/drivers/scsi/ibmvscsi/ibmvstgt.c +++ b/drivers/scsi/ibmvscsi/ibmvstgt.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -68,9 +69,12 @@ struct vio_port { unsigned long liobn; unsigned long riobn; struct srp_target *target; + + struct srp_rport *rport; }; static struct workqueue_struct *vtgtd; +static struct scsi_transport_template *ibmvstgt_transport_template; /* * These are fixed for the system and come from the Open Firmware device tree. @@ -188,6 +192,7 @@ static int send_rsp(struct iu_entry *iue, struct scsi_cmnd *sc, static void handle_cmd_queue(struct srp_target *target) { struct Scsi_Host *shost = target->shost; + struct srp_rport *rport = target_to_port(target)->rport; struct iu_entry *iue; struct srp_cmd *cmd; unsigned long flags; @@ -200,7 +205,8 @@ retry: if (!test_and_set_bit(V_FLYING, &iue->flags)) { spin_unlock_irqrestore(&target->lock, flags); cmd = iue->sbuf->buf; - err = srp_cmd_queue(shost, cmd, iue, 0); + err = srp_cmd_queue(shost, cmd, iue, + (unsigned long)rport, 0); if (err) { eprintk("cannot queue cmd %p %d\n", cmd, err); srp_iu_put(iue); @@ -359,6 +365,16 @@ static void process_login(struct iu_entry *iue) union viosrp_iu *iu = vio_iu(iue); struct srp_login_rsp *rsp = &iu->srp.login_rsp; uint64_t tag = iu->srp.rsp.tag; + struct Scsi_Host *shost = iue->target->shost; + struct srp_target *target = host_to_srp_target(shost); + struct vio_port *vport = target_to_port(target); + struct srp_rport_identifiers ids; + + memset(&ids, 0, sizeof(ids)); + sprintf(ids.port_id, "%x", vport->dma_dev->unit_address); + ids.roles = SRP_RPORT_ROLE_INITIATOR; + if (!vport->rport) + vport->rport = srp_rport_add(shost, &ids); /* TODO handle case that requested size is wrong and * buffer format is wrong @@ -412,7 +428,9 @@ static int process_tsk_mgmt(struct iu_entry *iue) fn = 0; } if (fn) - scsi_tgt_tsk_mgmt_request(iue->target->shost, fn, + scsi_tgt_tsk_mgmt_request(iue->target->shost, + (unsigned long)iue->target->shost, + fn, iu->srp.tsk_mgmt.task_tag, (struct scsi_lun *) &iu->srp.tsk_mgmt.lun, iue); @@ -721,7 +739,8 @@ static int ibmvstgt_eh_abort_handler(struct scsi_cmnd *sc) return 0; } -static int ibmvstgt_tsk_mgmt_response(u64 mid, int result) +static int ibmvstgt_tsk_mgmt_response(struct Scsi_Host *shost, + u64 itn_id, u64 mid, int result) { struct iu_entry *iue = (struct iu_entry *) ((void *) mid); union viosrp_iu *iu = vio_iu(iue); @@ -747,6 +766,20 @@ static int ibmvstgt_tsk_mgmt_response(u64 mid, int result) return 0; } +static int ibmvstgt_it_nexus_response(struct Scsi_Host *shost, u64 itn_id, + int result) +{ + struct srp_target *target = host_to_srp_target(shost); + struct vio_port *vport = target_to_port(target); + + if (result) { + eprintk("%p %d\n", shost, result); + srp_rport_del(vport->rport); + vport->rport = NULL; + } + return 0; +} + static ssize_t system_id_show(struct class_device *cdev, char *buf) { return snprintf(buf, PAGE_SIZE, "%s\n", system_id); @@ -804,6 +837,7 @@ static int ibmvstgt_probe(struct vio_dev *dev, const struct vio_device_id *id) shost = scsi_host_alloc(&ibmvstgt_sht, sizeof(struct srp_target)); if (!shost) goto free_vport; + shost->transportt = ibmvstgt_transport_template; err = scsi_tgt_alloc_queue(shost); if (err) goto put_host; @@ -837,8 +871,8 @@ static int ibmvstgt_probe(struct vio_dev *dev, const struct vio_device_id *id) err = scsi_add_host(shost, target->dev); if (err) goto destroy_queue; - return 0; + return 0; destroy_queue: crq_queue_destroy(target); free_srp_target: @@ -857,6 +891,7 @@ static int ibmvstgt_remove(struct vio_dev *dev) struct vio_port *vport = target->ldata; crq_queue_destroy(target); + srp_remove_host(shost); scsi_remove_host(shost); scsi_tgt_free_queue(shost); srp_target_free(target); @@ -909,15 +944,24 @@ static int get_system_info(void) return 0; } +static struct srp_function_template ibmvstgt_transport_functions = { + .it_nexus_response = ibmvstgt_it_nexus_response, +}; + static int ibmvstgt_init(void) { int err = -ENOMEM; printk("IBM eServer i/pSeries Virtual SCSI Target Driver\n"); + ibmvstgt_transport_template = + srp_attach_transport(&ibmvstgt_transport_functions); + if (!ibmvstgt_transport_template) + return err; + vtgtd = create_workqueue("ibmvtgtd"); if (!vtgtd) - return err; + goto release_transport; err = get_system_info(); if (err) @@ -928,9 +972,10 @@ static int ibmvstgt_init(void) goto destroy_wq; return 0; - destroy_wq: destroy_workqueue(vtgtd); +release_transport: + srp_release_transport(ibmvstgt_transport_template); return err; } @@ -940,6 +985,7 @@ static void ibmvstgt_exit(void) destroy_workqueue(vtgtd); vio_unregister_driver(&ibmvstgt_driver); + srp_release_transport(ibmvstgt_transport_template); } MODULE_DESCRIPTION("IBM Virtual SCSI Target"); diff --git a/drivers/scsi/libsrp.c b/drivers/scsi/libsrp.c index 732446e63963..2ad0a27dbaab 100644 --- a/drivers/scsi/libsrp.c +++ b/drivers/scsi/libsrp.c @@ -392,7 +392,7 @@ static int vscsis_data_length(struct srp_cmd *cmd, enum dma_data_direction dir) } int srp_cmd_queue(struct Scsi_Host *shost, struct srp_cmd *cmd, void *info, - u64 addr) + u64 itn_id, u64 addr) { enum dma_data_direction dir; struct scsi_cmnd *sc; @@ -428,7 +428,8 @@ int srp_cmd_queue(struct Scsi_Host *shost, struct srp_cmd *cmd, void *info, sc->request_bufflen = len; sc->request_buffer = (void *) (unsigned long) addr; sc->tag = tag; - err = scsi_tgt_queue_command(sc, (struct scsi_lun *) &cmd->lun, cmd->tag); + err = scsi_tgt_queue_command(sc, itn_id, (struct scsi_lun *)&cmd->lun, + cmd->tag); if (err) scsi_host_put_command(shost, sc); diff --git a/include/scsi/libsrp.h b/include/scsi/libsrp.h index d143171896ae..ba615e4c1d7c 100644 --- a/include/scsi/libsrp.h +++ b/include/scsi/libsrp.h @@ -59,7 +59,7 @@ extern void srp_target_free(struct srp_target *); extern struct iu_entry *srp_iu_get(struct srp_target *); extern void srp_iu_put(struct iu_entry *); -extern int srp_cmd_queue(struct Scsi_Host *, struct srp_cmd *, void *, u64); +extern int srp_cmd_queue(struct Scsi_Host *, struct srp_cmd *, void *, u64, u64); extern int srp_transfer_data(struct scsi_cmnd *, struct srp_cmd *, srp_rdma_t, int, int); -- cgit v1.2.3 From 0012fdf986c9b9c7fe8d0842a0ad8dd981a06c06 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Thu, 2 Aug 2007 00:20:34 +0900 Subject: [SCSI] scsi_transport_srp: remove tgt dependencies it's better to remove tgt dependencies in srp transport class since most people want only initiator support. Signed-off-by: FUJITA Tomonori Signed-off-by: James Bottomley --- drivers/scsi/Kconfig | 11 +++++++++-- drivers/scsi/scsi_transport_srp.c | 10 +++++----- drivers/scsi/scsi_transport_srp_internal.h | 25 +++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 7 deletions(-) create mode 100644 drivers/scsi/scsi_transport_srp_internal.h (limited to 'drivers/scsi/Kconfig') diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 4562273dfad3..7877dfdd2322 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -291,11 +291,18 @@ source "drivers/scsi/libsas/Kconfig" config SCSI_SRP_ATTRS tristate "SRP Transport Attributes" - depends on SCSI && SCSI_TGT + depends on SCSI help If you wish to export transport-specific information about each attached SRP device to sysfs, say Y. +config SCSI_SRP_TGT_ATTRS + bool "SCSI target support for SRP Transport Attributes" + depends on SCSI_SRP_ATTRS + depends on SCSI_TGT = y || SCSI_TGT = SCSI_SRP_ATTRS + help + If you want to use SCSI target mode drivers enable this option. + endmenu menuconfig SCSI_LOWLEVEL @@ -848,7 +855,7 @@ config SCSI_IBMVSCSI config SCSI_IBMVSCSIS tristate "IBM Virtual SCSI Server support" - depends on PPC_PSERIES && SCSI_TGT && SCSI_SRP && SCSI_SRP_ATTRS + depends on PPC_PSERIES && SCSI_SRP && SCSI_SRP_TGT_ATTRS help This is the SRP target driver for IBM pSeries virtual environments. diff --git a/drivers/scsi/scsi_transport_srp.c b/drivers/scsi/scsi_transport_srp.c index cdd001a6639c..430501ef9f02 100644 --- a/drivers/scsi/scsi_transport_srp.c +++ b/drivers/scsi/scsi_transport_srp.c @@ -30,7 +30,7 @@ #include #include #include -#include +#include "scsi_transport_srp_internal.h" struct srp_host_attrs { atomic_t next_port_id; @@ -223,8 +223,8 @@ struct srp_rport *srp_rport_add(struct Scsi_Host *shost, } if (ids->roles == SRP_RPORT_ROLE_INITIATOR) { - ret = scsi_tgt_it_nexus_create(shost, (unsigned long)rport, - rport->port_id); + ret = srp_tgt_it_nexus_create(shost, (unsigned long)rport, + rport->port_id); if (ret) { device_del(&rport->dev); transport_destroy_device(&rport->dev); @@ -251,8 +251,8 @@ void srp_rport_del(struct srp_rport *rport) struct device *dev = &rport->dev; if (rport->roles == SRP_RPORT_ROLE_INITIATOR) - scsi_tgt_it_nexus_destroy(dev_to_shost(dev->parent), - (unsigned long)rport); + srp_tgt_it_nexus_destroy(dev_to_shost(dev->parent), + (unsigned long)rport); transport_remove_device(dev); device_del(dev); diff --git a/drivers/scsi/scsi_transport_srp_internal.h b/drivers/scsi/scsi_transport_srp_internal.h new file mode 100644 index 000000000000..8a79747f9f3d --- /dev/null +++ b/drivers/scsi/scsi_transport_srp_internal.h @@ -0,0 +1,25 @@ +#include + +#ifdef CONFIG_SCSI_SRP_TGT_ATTRS +static inline int srp_tgt_it_nexus_create(struct Scsi_Host *shost, u64 itn_id, + char *initiator) +{ + return scsi_tgt_it_nexus_create(shost, itn_id, initiator); +} + +static inline int srp_tgt_it_nexus_destroy(struct Scsi_Host *shost, u64 itn_id) +{ + return scsi_tgt_it_nexus_destroy(shost, itn_id); +} + +#else +static inline int srp_tgt_it_nexus_create(struct Scsi_Host *shost, u64 itn_id, + char *initiator) +{ + return 0; +} +static inline int srp_tgt_it_nexus_destroy(struct Scsi_Host *shost, u64 itn_id) +{ + return 0; +} +#endif -- cgit v1.2.3 From 7525236d0bc7ad17eb5e0733417896cab745d6c8 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Sat, 1 Sep 2007 02:02:27 +0900 Subject: [SCSI] fc_transport: add target driver support This adds minimum target driver support like the srp transport does: - fc_remote_port_{rolechg,delete} calls scsi_tgt_it_nexus_{create,destroy} for target drivers. - add callbacks to notify target drivers of the nexus and tmf operation results to fc_function_template. Signed-off-by: FUJITA Tomonori Signed-off-by: Mike Christie Signed-off-by: James Bottomley --- drivers/scsi/Kconfig | 7 +++++++ drivers/scsi/scsi_transport_fc.c | 29 +++++++++++++++++++++++++++++ drivers/scsi/scsi_transport_fc_internal.h | 26 ++++++++++++++++++++++++++ include/scsi/scsi_transport_fc.h | 4 ++++ 4 files changed, 66 insertions(+) create mode 100644 drivers/scsi/scsi_transport_fc_internal.h (limited to 'drivers/scsi/Kconfig') diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 7877dfdd2322..e1efa0eac4ff 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -272,6 +272,13 @@ config SCSI_FC_ATTRS each attached FiberChannel device to sysfs, say Y. Otherwise, say N. +config SCSI_FC_TGT_ATTRS + bool "SCSI target support for FiberChannel Transport Attributes" + depends on SCSI_FC_ATTRS + depends on SCSI_TGT = y || SCSI_TGT = SCSI_FC_ATTRS + help + If you want to use SCSI target mode drivers enable this option. + config SCSI_ISCSI_ATTRS tristate "iSCSI Transport Attributes" depends on SCSI && NET diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c index dd97f2652508..8df0f080997f 100644 --- a/drivers/scsi/scsi_transport_fc.c +++ b/drivers/scsi/scsi_transport_fc.c @@ -36,6 +36,7 @@ #include #include #include "scsi_priv.h" +#include "scsi_transport_fc_internal.h" static int fc_queue_work(struct Scsi_Host *, struct work_struct *); static void fc_vport_sched_delete(struct work_struct *work); @@ -1956,6 +1957,19 @@ static int fc_user_scan(struct Scsi_Host *shost, uint channel, return 0; } +static int fc_tsk_mgmt_response(struct Scsi_Host *shost, u64 nexus, u64 tm_id, + int result) +{ + struct fc_internal *i = to_fc_internal(shost->transportt); + return i->f->tsk_mgmt_response(shost, nexus, tm_id, result); +} + +static int fc_it_nexus_response(struct Scsi_Host *shost, u64 nexus, int result) +{ + struct fc_internal *i = to_fc_internal(shost->transportt); + return i->f->it_nexus_response(shost, nexus, result); +} + struct scsi_transport_template * fc_attach_transport(struct fc_function_template *ft) { @@ -1999,6 +2013,10 @@ fc_attach_transport(struct fc_function_template *ft) i->t.user_scan = fc_user_scan; + /* target-mode drivers' functions */ + i->t.tsk_mgmt_response = fc_tsk_mgmt_response; + i->t.it_nexus_response = fc_it_nexus_response; + /* * Setup SCSI Target Attributes. */ @@ -2756,6 +2774,10 @@ fc_remote_port_delete(struct fc_rport *rport) spin_unlock_irqrestore(shost->host_lock, flags); + if (rport->roles & FC_PORT_ROLE_FCP_INITIATOR && + shost->active_mode & MODE_TARGET) + fc_tgt_it_nexus_destroy(shost, (unsigned long)rport); + scsi_target_block(&rport->dev); /* see if we need to kill io faster than waiting for device loss */ @@ -2796,6 +2818,7 @@ fc_remote_port_rolechg(struct fc_rport *rport, u32 roles) struct fc_host_attrs *fc_host = shost_to_fc_host(shost); unsigned long flags; int create = 0; + int ret; spin_lock_irqsave(shost->host_lock, flags); if (roles & FC_PORT_ROLE_FCP_TARGET) { @@ -2804,6 +2827,12 @@ fc_remote_port_rolechg(struct fc_rport *rport, u32 roles) create = 1; } else if (!(rport->roles & FC_PORT_ROLE_FCP_TARGET)) create = 1; + } else if (shost->active_mode & MODE_TARGET) { + ret = fc_tgt_it_nexus_create(shost, (unsigned long)rport, + (char *)&rport->node_name); + if (ret) + printk(KERN_ERR "FC Remore Port tgt nexus failed %d\n", + ret); } rport->roles = roles; diff --git a/drivers/scsi/scsi_transport_fc_internal.h b/drivers/scsi/scsi_transport_fc_internal.h new file mode 100644 index 000000000000..e7bfbe751c1f --- /dev/null +++ b/drivers/scsi/scsi_transport_fc_internal.h @@ -0,0 +1,26 @@ +#include + +#ifdef CONFIG_SCSI_FC_TGT_ATTRS +static inline int fc_tgt_it_nexus_create(struct Scsi_Host *shost, u64 itn_id, + char *initiator) +{ + return scsi_tgt_it_nexus_create(shost, itn_id, initiator); +} + +static inline int fc_tgt_it_nexus_destroy(struct Scsi_Host *shost, u64 itn_id) +{ + return scsi_tgt_it_nexus_destroy(shost, itn_id); +} +#else +static inline int fc_tgt_it_nexus_create(struct Scsi_Host *shost, u64 itn_id, + char *initiator) +{ + return 0; +} + +static inline int fc_tgt_it_nexus_destroy(struct Scsi_Host *shost, u64 itn_id) +{ + return 0; +} + +#endif diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h index 616a96a3ab81..e466d886e192 100644 --- a/include/scsi/scsi_transport_fc.h +++ b/include/scsi/scsi_transport_fc.h @@ -589,6 +589,10 @@ struct fc_function_template { int (*vport_disable)(struct fc_vport *, bool); int (*vport_delete)(struct fc_vport *); + /* target-mode drivers' functions */ + int (* tsk_mgmt_response)(struct Scsi_Host *, u64, u64, int); + int (* it_nexus_response)(struct Scsi_Host *, u64, int); + /* allocation lengths for host-specific data */ u32 dd_fcrport_size; u32 dd_fcvport_size; -- cgit v1.2.3 From 1a4f550a09f89e3a15eff1971bc9db977571b9f6 Mon Sep 17 00:00:00 2001 From: Nick Cheng Date: Thu, 13 Sep 2007 17:26:40 +0800 Subject: [SCSI] arcmsr: 1.20.00.15: add SATA RAID plus other fixes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Description: ** support ARC1200/1201/1202 SATA RAID adapter, which is named ACB_ADAPTER_TYPE_B ** modify the arcmsr_pci_slot_reset function ** modify the arcmsr_pci_ers_disconnect_forepart function ** modify the arcmsr_pci_ers_need_reset_forepart function  Signed-off-by: Nick Cheng Signed-off-by: James Bottomley --- Documentation/scsi/ChangeLog.arcmsr | 17 +- drivers/scsi/Kconfig | 23 +- drivers/scsi/arcmsr/arcmsr.h | 192 ++- drivers/scsi/arcmsr/arcmsr_attr.c | 64 +- drivers/scsi/arcmsr/arcmsr_hba.c | 2263 +++++++++++++++++++++-------------- include/linux/pci_ids.h | 3 + 6 files changed, 1571 insertions(+), 991 deletions(-) (limited to 'drivers/scsi/Kconfig') diff --git a/Documentation/scsi/ChangeLog.arcmsr b/Documentation/scsi/ChangeLog.arcmsr index 162c47fdf45f..cd8403a33ee6 100644 --- a/Documentation/scsi/ChangeLog.arcmsr +++ b/Documentation/scsi/ChangeLog.arcmsr @@ -53,4 +53,19 @@ ** for linux standard list ** enable usage of pci message signal interrupt ** follow Randy.Danlup kindness suggestion cleanup this code -************************************************************************** \ No newline at end of file +** 1.20.00.14 05/02/2007 Erich Chen & Nick Cheng +** 1.implement PCI-Express error recovery function and AER capability +** 2.implement the selection of ARCMSR_MAX_XFER_SECTORS_B=4096 +** if firmware version is newer than 1.42 +** 3.modify arcmsr_iop_reset to improve the ability +** 4.modify the ISR, arcmsr_interrupt routine,to prevent the +** inconsistency with sg_mod driver if application directly calls +** the arcmsr driver w/o passing through scsi mid layer +** specially thanks to Yanmin Zhang's openhanded help about AER +** 1.20.00.15 08/30/2007 Erich Chen & Nick Cheng +** 1. support ARC1200/1201/1202 SATA RAID adapter, which is named +** ACB_ADAPTER_TYPE_B +** 2. modify the arcmsr_pci_slot_reset function +** 3. modify the arcmsr_pci_ers_disconnect_forepart function +** 4. modify the arcmsr_pci_ers_need_reset_forepart function +************************************************************************** diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index e1efa0eac4ff..69b2fac6f098 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -543,19 +543,32 @@ config SCSI_IN2000 module will be called in2000. config SCSI_ARCMSR - tristate "ARECA ARC11X0[PCI-X]/ARC12X0[PCI-EXPRESS] SATA-RAID support" + tristate "ARECA (ARC11xx/12xx/13xx/16xx) SATA/SAS RAID Host Adapter" depends on PCI && SCSI help - This driver supports all of ARECA's SATA RAID controller cards. + This driver supports all of ARECA's SATA/SAS RAID controller cards. This is an ARECA-maintained driver by Erich Chen. - If you have any problems, please mail to: < erich@areca.com.tw > + If you have any problems, please mail to: . Areca supports Linux RAID config tools. - - < http://www.areca.com.tw > + Please link To compile this driver as a module, choose M here: the module will be called arcmsr (modprobe arcmsr). +config SCSI_ARCMSR_AER + bool "Enable PCI Error Recovery Capability in Areca Driver(ARCMSR)" + depends on SCSI_ARCMSR && PCIEAER + default n + help + The advanced error reporting(AER) capability is "NOT" provided by + ARC1200/1201/1202 SATA RAID controllers cards. + If your card is one of ARC1200/1201/1202, please use the default setting, n. + If your card is other models, you could pick it + on condition that the kernel version is greater than 2.6.19. + This function is maintained driver by Nick Cheng. If you have any + problems or suggestion, you are welcome to contact with . + To enable this function, choose Y here. + source "drivers/scsi/megaraid/Kconfig.megaraid" config SCSI_HPTIOP diff --git a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h index f0b8bf4534f0..ace7a15b413e 100644 --- a/drivers/scsi/arcmsr/arcmsr.h +++ b/drivers/scsi/arcmsr/arcmsr.h @@ -9,7 +9,7 @@ ** Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved. ** ** Web site: www.areca.com.tw -** E-mail: erich@areca.com.tw +** E-mail: support@areca.com.tw ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License version 2 as @@ -45,19 +45,26 @@ #include struct class_device_attribute; - -#define ARCMSR_MAX_OUTSTANDING_CMD 256 -#define ARCMSR_MAX_FREECCB_NUM 288 -#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.14" +/*The limit of outstanding scsi command that firmware can handle*/ +#define ARCMSR_MAX_OUTSTANDING_CMD 256 +#define ARCMSR_MAX_FREECCB_NUM 320 +#define ARCMSR_DRIVER_VERSION "Driver Version 1.20.00.15 2007/08/30" #define ARCMSR_SCSI_INITIATOR_ID 255 #define ARCMSR_MAX_XFER_SECTORS 512 -#define ARCMSR_MAX_XFER_SECTORS_B 4096 -#define ARCMSR_MAX_TARGETID 17 -#define ARCMSR_MAX_TARGETLUN 8 -#define ARCMSR_MAX_CMD_PERLUN ARCMSR_MAX_OUTSTANDING_CMD -#define ARCMSR_MAX_QBUFFER 4096 -#define ARCMSR_MAX_SG_ENTRIES 38 - +#define ARCMSR_MAX_XFER_SECTORS_B 4096 +#define ARCMSR_MAX_TARGETID 17 +#define ARCMSR_MAX_TARGETLUN 8 +#define ARCMSR_MAX_CMD_PERLUN ARCMSR_MAX_OUTSTANDING_CMD +#define ARCMSR_MAX_QBUFFER 4096 +#define ARCMSR_MAX_SG_ENTRIES 38 +#define ARCMSR_MAX_HBB_POSTQUEUE 264 +/* +********************************************************************************** +** +********************************************************************************** +*/ +#define ARC_SUCCESS 0 +#define ARC_FAILURE 1 /* ******************************************************************************* ** split 64bits dma addressing @@ -90,7 +97,7 @@ struct CMD_MESSAGE_FIELD uint8_t messagedatabuffer[1032]; }; /* IOP message transfer */ -#define ARCMSR_MESSAGE_FAIL 0x0001 +#define ARCMSR_MESSAGE_FAIL 0x0001 /* DeviceType */ #define ARECA_SATA_RAID 0x90000000 /* FunctionCode */ @@ -163,27 +170,27 @@ struct QBUFFER }; /* ******************************************************************************* -** FIRMWARE INFO +** FIRMWARE INFO for Intel IOP R 80331 processor (Type A) ******************************************************************************* */ struct FIRMWARE_INFO { - uint32_t signature; /*0, 00-03*/ - uint32_t request_len; /*1, 04-07*/ - uint32_t numbers_queue; /*2, 08-11*/ + uint32_t signature; /*0, 00-03*/ + uint32_t request_len; /*1, 04-07*/ + uint32_t numbers_queue; /*2, 08-11*/ uint32_t sdram_size; /*3, 12-15*/ - uint32_t ide_channels; /*4, 16-19*/ - char vendor[40]; /*5, 20-59*/ - char model[8]; /*15, 60-67*/ - char firmware_ver[16]; /*17, 68-83*/ - char device_map[16]; /*21, 84-99*/ + uint32_t ide_channels; /*4, 16-19*/ + char vendor[40]; /*5, 20-59*/ + char model[8]; /*15, 60-67*/ + char firmware_ver[16]; /*17, 68-83*/ + char device_map[16]; /*21, 84-99*/ }; /* signature of set and get firmware config */ -#define ARCMSR_SIGNATURE_GET_CONFIG 0x87974060 -#define ARCMSR_SIGNATURE_SET_CONFIG 0x87974063 +#define ARCMSR_SIGNATURE_GET_CONFIG 0x87974060 +#define ARCMSR_SIGNATURE_SET_CONFIG 0x87974063 /* message code of inbound message register */ -#define ARCMSR_INBOUND_MESG0_NOP 0x00000000 -#define ARCMSR_INBOUND_MESG0_GET_CONFIG 0x00000001 +#define ARCMSR_INBOUND_MESG0_NOP 0x00000000 +#define ARCMSR_INBOUND_MESG0_GET_CONFIG 0x00000001 #define ARCMSR_INBOUND_MESG0_SET_CONFIG 0x00000002 #define ARCMSR_INBOUND_MESG0_ABORT_CMD 0x00000003 #define ARCMSR_INBOUND_MESG0_STOP_BGRB 0x00000004 @@ -203,6 +210,60 @@ struct FIRMWARE_INFO #define ARCMSR_CCBREPLY_FLAG_ERROR 0x10000000 /* outbound firmware ok */ #define ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK 0x80000000 + +/* +************************************************************************ +** SPEC. for Areca Type B adapter +************************************************************************ +*/ +/* ARECA HBB COMMAND for its FIRMWARE */ +/* window of "instruction flags" from driver to iop */ +#define ARCMSR_DRV2IOP_DOORBELL 0x00020400 +#define ARCMSR_DRV2IOP_DOORBELL_MASK 0x00020404 +/* window of "instruction flags" from iop to driver */ +#define ARCMSR_IOP2DRV_DOORBELL 0x00020408 +#define ARCMSR_IOP2DRV_DOORBELL_MASK 0x0002040C +/* ARECA FLAG LANGUAGE */ +/* ioctl transfer */ +#define ARCMSR_IOP2DRV_DATA_WRITE_OK 0x00000001 +/* ioctl transfer */ +#define ARCMSR_IOP2DRV_DATA_READ_OK 0x00000002 +#define ARCMSR_IOP2DRV_CDB_DONE 0x00000004 +#define ARCMSR_IOP2DRV_MESSAGE_CMD_DONE 0x00000008 + +#define ARCMSR_DOORBELL_HANDLE_INT 0x0000000F +#define ARCMSR_DOORBELL_INT_CLEAR_PATTERN 0xFF00FFF0 +#define ARCMSR_MESSAGE_INT_CLEAR_PATTERN 0xFF00FFF7 +/* (ARCMSR_INBOUND_MESG0_GET_CONFIG<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */ +#define ARCMSR_MESSAGE_GET_CONFIG 0x00010008 +/* (ARCMSR_INBOUND_MESG0_SET_CONFIG<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */ +#define ARCMSR_MESSAGE_SET_CONFIG 0x00020008 +/* (ARCMSR_INBOUND_MESG0_ABORT_CMD<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */ +#define ARCMSR_MESSAGE_ABORT_CMD 0x00030008 +/* (ARCMSR_INBOUND_MESG0_STOP_BGRB<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */ +#define ARCMSR_MESSAGE_STOP_BGRB 0x00040008 +/* (ARCMSR_INBOUND_MESG0_FLUSH_CACHE<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */ +#define ARCMSR_MESSAGE_FLUSH_CACHE 0x00050008 +/* (ARCMSR_INBOUND_MESG0_START_BGRB<<16)|ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED) */ +#define ARCMSR_MESSAGE_START_BGRB 0x00060008 +#define ARCMSR_MESSAGE_START_DRIVER_MODE 0x000E0008 +#define ARCMSR_MESSAGE_SET_POST_WINDOW 0x000F0008 +/* ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK */ +#define ARCMSR_MESSAGE_FIRMWARE_OK 0x80000000 +/* ioctl transfer */ +#define ARCMSR_DRV2IOP_DATA_WRITE_OK 0x00000001 +/* ioctl transfer */ +#define ARCMSR_DRV2IOP_DATA_READ_OK 0x00000002 +#define ARCMSR_DRV2IOP_CDB_POSTED 0x00000004 +#define ARCMSR_DRV2IOP_MESSAGE_CMD_POSTED 0x00000008 + +/* data tunnel buffer between user space program and its firmware */ +/* user space data to iop 128bytes */ +#define ARCMSR_IOCTL_WBUFFER 0x0000fe00 +/* iop data to user space 128bytes */ +#define ARCMSR_IOCTL_RBUFFER 0x0000ff00 +/* iop message_rwbuffer for message command */ +#define ARCMSR_MSGCODE_RWBUFFER 0x0000fa00 /* ******************************************************************************* ** ARECA SCSI COMMAND DESCRIPTOR BLOCK size 0x1F8 (504) @@ -214,7 +275,6 @@ struct ARCMSR_CDB uint8_t TargetID; uint8_t LUN; uint8_t Function; - uint8_t CdbLength; uint8_t sgcount; uint8_t Flags; @@ -224,20 +284,18 @@ struct ARCMSR_CDB #define ARCMSR_CDB_FLAG_SIMPLEQ 0x00 #define ARCMSR_CDB_FLAG_HEADQ 0x08 #define ARCMSR_CDB_FLAG_ORDEREDQ 0x10 - uint8_t Reserved1; + uint8_t Reserved1; uint32_t Context; uint32_t DataLength; - uint8_t Cdb[16]; - uint8_t DeviceStatus; -#define ARCMSR_DEV_CHECK_CONDITION 0x02 -#define ARCMSR_DEV_SELECT_TIMEOUT 0xF0 -#define ARCMSR_DEV_ABORTED 0xF1 -#define ARCMSR_DEV_INIT_FAIL 0xF2 - uint8_t SenseData[15]; +#define ARCMSR_DEV_CHECK_CONDITION 0x02 +#define ARCMSR_DEV_SELECT_TIMEOUT 0xF0 +#define ARCMSR_DEV_ABORTED 0xF1 +#define ARCMSR_DEV_INIT_FAIL 0xF2 + uint8_t SenseData[15]; union { struct SG32ENTRY sg32entry[ARCMSR_MAX_SG_ENTRIES]; @@ -246,10 +304,10 @@ struct ARCMSR_CDB }; /* ******************************************************************************* -** Messaging Unit (MU) of the Intel R 80331 I/O processor (80331) +** Messaging Unit (MU) of the Intel R 80331 I/O processor(Type A) and Type B processor ******************************************************************************* */ -struct MessageUnit +struct MessageUnit_A { uint32_t resrved0[4]; /*0000 000F*/ uint32_t inbound_msgaddr0; /*0010 0013*/ @@ -274,6 +332,30 @@ struct MessageUnit uint32_t message_rbuffer[32]; /*0F00 0F7F 32*/ uint32_t reserved6[32]; /*0F80 0FFF 32*/ }; + +struct MessageUnit_B +{ + uint32_t post_qbuffer[ARCMSR_MAX_HBB_POSTQUEUE]; + uint32_t done_qbuffer[ARCMSR_MAX_HBB_POSTQUEUE]; + uint32_t postq_index; + uint32_t doneq_index; + uint32_t *drv2iop_doorbell_reg; + uint32_t *drv2iop_doorbell_mask_reg; + uint32_t *iop2drv_doorbell_reg; + uint32_t *iop2drv_doorbell_mask_reg; + uint32_t *msgcode_rwbuffer_reg; + uint32_t *ioctl_wbuffer_reg; + uint32_t *ioctl_rbuffer_reg; +}; + +struct MessageUnit +{ + union + { + struct MessageUnit_A pmu_A; + struct MessageUnit_B pmu_B; + } u; +}; /* ******************************************************************************* ** Adapter Control Block @@ -281,37 +363,45 @@ struct MessageUnit */ struct AdapterControlBlock { + uint32_t adapter_type; /* adapter A,B..... */ + #define ACB_ADAPTER_TYPE_A 0x00000001 /* hba I IOP */ + #define ACB_ADAPTER_TYPE_B 0x00000002 /* hbb M IOP */ + #define ACB_ADAPTER_TYPE_C 0x00000004 /* hbc P IOP */ + #define ACB_ADAPTER_TYPE_D 0x00000008 /* hbd A IOP */ struct pci_dev * pdev; struct Scsi_Host * host; unsigned long vir2phy_offset; /* Offset is used in making arc cdb physical to virtual calculations */ uint32_t outbound_int_enable; - struct MessageUnit __iomem * pmu; + struct MessageUnit * pmu; /* message unit ATU inbound base address0 */ uint32_t acb_flags; -#define ACB_F_SCSISTOPADAPTER 0x0001 -#define ACB_F_MSG_STOP_BGRB 0x0002 + #define ACB_F_SCSISTOPADAPTER 0x0001 + #define ACB_F_MSG_STOP_BGRB 0x0002 /* stop RAID background rebuild */ -#define ACB_F_MSG_START_BGRB 0x0004 + #define ACB_F_MSG_START_BGRB 0x0004 /* stop RAID background rebuild */ -#define ACB_F_IOPDATA_OVERFLOW 0x0008 + #define ACB_F_IOPDATA_OVERFLOW 0x0008 /* iop message data rqbuffer overflow */ -#define ACB_F_MESSAGE_WQBUFFER_CLEARED 0x0010 + #define ACB_F_MESSAGE_WQBUFFER_CLEARED 0x0010 /* message clear wqbuffer */ -#define ACB_F_MESSAGE_RQBUFFER_CLEARED 0x0020 + #define ACB_F_MESSAGE_RQBUFFER_CLEARED 0x0020 /* message clear rqbuffer */ -#define ACB_F_MESSAGE_WQBUFFER_READED 0x0040 -#define ACB_F_BUS_RESET 0x0080 -#define ACB_F_IOP_INITED 0x0100 + #define ACB_F_MESSAGE_WQBUFFER_READED 0x0040 + #define ACB_F_BUS_RESET 0x0080 + #define ACB_F_IOP_INITED 0x0100 /* iop init */ struct CommandControlBlock * pccb_pool[ARCMSR_MAX_FREECCB_NUM]; /* used for memory free */ struct list_head ccb_free_list; /* head of free ccb list */ + atomic_t ccboutstandingcount; + /*The present outstanding command number that in the IOP that + waiting for being handled by FW*/ void * dma_coherent; /* dma_coherent used for memory free */ @@ -353,7 +443,7 @@ struct CommandControlBlock { struct ARCMSR_CDB arcmsr_cdb; /* - ** 0-503 (size of CDB=504): + ** 0-503 (size of CDB = 504): ** arcmsr messenger scsi command descriptor size 504 bytes */ uint32_t cdb_shifted_phyaddr; @@ -466,7 +556,9 @@ struct SENSE_DATA #define ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE 0x01 #define ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE 0x1F -extern void arcmsr_post_Qbuffer(struct AdapterControlBlock *acb); +extern void arcmsr_post_ioctldata2iop(struct AdapterControlBlock *); +extern void arcmsr_iop_message_read(struct AdapterControlBlock *); +extern struct QBUFFER *arcmsr_get_iop_rqbuffer(struct AdapterControlBlock *); extern struct class_device_attribute *arcmsr_host_attrs[]; -extern int arcmsr_alloc_sysfs_attr(struct AdapterControlBlock *acb); +extern int arcmsr_alloc_sysfs_attr(struct AdapterControlBlock *); void arcmsr_free_sysfs_attr(struct AdapterControlBlock *acb); diff --git a/drivers/scsi/arcmsr/arcmsr_attr.c b/drivers/scsi/arcmsr/arcmsr_attr.c index 06c0dce3b839..0f0a1ae99434 100644 --- a/drivers/scsi/arcmsr/arcmsr_attr.c +++ b/drivers/scsi/arcmsr/arcmsr_attr.c @@ -8,7 +8,7 @@ ** Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved ** ** Web site: www.areca.com.tw -** E-mail: erich@areca.com.tw +** E-mail: support@areca.com.tw ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License version 2 as @@ -49,6 +49,7 @@ #include #include #include +#include #include #include @@ -58,15 +59,11 @@ struct class_device_attribute *arcmsr_host_attrs[]; -static ssize_t -arcmsr_sysfs_iop_message_read(struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) +static ssize_t arcmsr_sysfs_iop_message_read(struct kobject *kobj, char *buf, loff_t off, size_t count) { struct class_device *cdev = container_of(kobj,struct class_device,kobj); struct Scsi_Host *host = class_to_shost(cdev); struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; - struct MessageUnit __iomem *reg = acb->pmu; uint8_t *pQbuffer,*ptmpQbuffer; int32_t allxfer_len = 0; @@ -85,12 +82,13 @@ arcmsr_sysfs_iop_message_read(struct kobject *kobj, allxfer_len++; } if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { - struct QBUFFER __iomem * prbuffer = (struct QBUFFER __iomem *) - ®->message_rbuffer; - uint8_t __iomem * iop_data = (uint8_t __iomem *)prbuffer->data; + struct QBUFFER *prbuffer; + uint8_t *iop_data; int32_t iop_len; acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; + prbuffer = arcmsr_get_iop_rqbuffer(acb); + iop_data = (uint8_t *)prbuffer->data; iop_len = readl(&prbuffer->data_len); while (iop_len > 0) { acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data); @@ -99,16 +97,12 @@ arcmsr_sysfs_iop_message_read(struct kobject *kobj, iop_data++; iop_len--; } - writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, - ®->inbound_doorbell); + arcmsr_iop_message_read(acb); } return (allxfer_len); } -static ssize_t -arcmsr_sysfs_iop_message_write(struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) +static ssize_t arcmsr_sysfs_iop_message_write(struct kobject *kobj, char *buf, loff_t off, size_t count) { struct class_device *cdev = container_of(kobj,struct class_device,kobj); struct Scsi_Host *host = class_to_shost(cdev); @@ -126,7 +120,7 @@ arcmsr_sysfs_iop_message_write(struct kobject *kobj, wqbuf_lastindex = acb->wqbuf_lastindex; wqbuf_firstindex = acb->wqbuf_firstindex; if (wqbuf_lastindex != wqbuf_firstindex) { - arcmsr_post_Qbuffer(acb); + arcmsr_post_ioctldata2iop(acb); return 0; /*need retry*/ } else { my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1) @@ -144,7 +138,7 @@ arcmsr_sysfs_iop_message_write(struct kobject *kobj, if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) { acb->acb_flags &= ~ACB_F_MESSAGE_WQBUFFER_CLEARED; - arcmsr_post_Qbuffer(acb); + arcmsr_post_ioctldata2iop(acb); } return count; } else { @@ -153,15 +147,11 @@ arcmsr_sysfs_iop_message_write(struct kobject *kobj, } } -static ssize_t -arcmsr_sysfs_iop_message_clear(struct kobject *kobj, - struct bin_attribute *bin_attr, - char *buf, loff_t off, size_t count) +static ssize_t arcmsr_sysfs_iop_message_clear(struct kobject *kobj, char *buf, loff_t off, size_t count) { struct class_device *cdev = container_of(kobj,struct class_device,kobj); struct Scsi_Host *host = class_to_shost(cdev); struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; - struct MessageUnit __iomem *reg = acb->pmu; uint8_t *pQbuffer; if (!capable(CAP_SYS_ADMIN)) @@ -169,8 +159,7 @@ arcmsr_sysfs_iop_message_clear(struct kobject *kobj, if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; - writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK - , ®->inbound_doorbell); + arcmsr_iop_message_read(acb); } acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED @@ -191,6 +180,7 @@ static struct bin_attribute arcmsr_sysfs_message_read_attr = { .attr = { .name = "mu_read", .mode = S_IRUSR , + .owner = THIS_MODULE, }, .size = 1032, .read = arcmsr_sysfs_iop_message_read, @@ -200,6 +190,7 @@ static struct bin_attribute arcmsr_sysfs_message_write_attr = { .attr = { .name = "mu_write", .mode = S_IWUSR, + .owner = THIS_MODULE, }, .size = 1032, .write = arcmsr_sysfs_iop_message_write, @@ -209,6 +200,7 @@ static struct bin_attribute arcmsr_sysfs_message_clear_attr = { .attr = { .name = "mu_clear", .mode = S_IWUSR, + .owner = THIS_MODULE, }, .size = 1, .write = arcmsr_sysfs_iop_message_clear, @@ -219,31 +211,26 @@ int arcmsr_alloc_sysfs_attr(struct AdapterControlBlock *acb) struct Scsi_Host *host = acb->host; int error; - error = sysfs_create_bin_file(&host->shost_classdev.kobj, - &arcmsr_sysfs_message_read_attr); + error = sysfs_create_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_read_attr); if (error) { printk(KERN_ERR "arcmsr: alloc sysfs mu_read failed\n"); goto error_bin_file_message_read; } - error = sysfs_create_bin_file(&host->shost_classdev.kobj, - &arcmsr_sysfs_message_write_attr); + error = sysfs_create_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_write_attr); if (error) { printk(KERN_ERR "arcmsr: alloc sysfs mu_write failed\n"); goto error_bin_file_message_write; } - error = sysfs_create_bin_file(&host->shost_classdev.kobj, - &arcmsr_sysfs_message_clear_attr); + error = sysfs_create_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_clear_attr); if (error) { printk(KERN_ERR "arcmsr: alloc sysfs mu_clear failed\n"); goto error_bin_file_message_clear; } return 0; error_bin_file_message_clear: - sysfs_remove_bin_file(&host->shost_classdev.kobj, - &arcmsr_sysfs_message_write_attr); + sysfs_remove_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_write_attr); error_bin_file_message_write: - sysfs_remove_bin_file(&host->shost_classdev.kobj, - &arcmsr_sysfs_message_read_attr); + sysfs_remove_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_read_attr); error_bin_file_message_read: return error; } @@ -252,12 +239,9 @@ void arcmsr_free_sysfs_attr(struct AdapterControlBlock *acb) { struct Scsi_Host *host = acb->host; - sysfs_remove_bin_file(&host->shost_classdev.kobj, - &arcmsr_sysfs_message_clear_attr); - sysfs_remove_bin_file(&host->shost_classdev.kobj, - &arcmsr_sysfs_message_write_attr); - sysfs_remove_bin_file(&host->shost_classdev.kobj, - &arcmsr_sysfs_message_read_attr); + sysfs_remove_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_clear_attr); + sysfs_remove_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_write_attr); + sysfs_remove_bin_file(&host->shost_classdev.kobj, &arcmsr_sysfs_message_read_attr); } diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index 0ddfc21e9f7d..d70398ac64db 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -9,7 +9,7 @@ ** Copyright (C) 2002 - 2005, Areca Technology Corporation All rights reserved ** ** Web site: www.areca.com.tw -** E-mail: erich@areca.com.tw +** E-mail: support@areca.com.tw ** ** This program is free software; you can redistribute it and/or modify ** it under the terms of the GNU General Public License version 2 as @@ -71,33 +71,37 @@ #include #include "arcmsr.h" -MODULE_AUTHOR("Erich Chen "); +MODULE_AUTHOR("Erich Chen "); MODULE_DESCRIPTION("ARECA (ARC11xx/12xx/13xx/16xx) SATA/SAS RAID HOST Adapter"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_VERSION(ARCMSR_DRIVER_VERSION); -static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, struct scsi_cmnd *cmd); +static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, + struct scsi_cmnd *cmd); +static int arcmsr_iop_confirm(struct AdapterControlBlock *acb); static int arcmsr_abort(struct scsi_cmnd *); static int arcmsr_bus_reset(struct scsi_cmnd *); static int arcmsr_bios_param(struct scsi_device *sdev, - struct block_device *bdev, sector_t capacity, int *info); -static int arcmsr_queue_command(struct scsi_cmnd * cmd, - void (*done) (struct scsi_cmnd *)); + struct block_device *bdev, sector_t capacity, int *info); +static int arcmsr_queue_command(struct scsi_cmnd *cmd, + void (*done) (struct scsi_cmnd *)); static int arcmsr_probe(struct pci_dev *pdev, const struct pci_device_id *id); static void arcmsr_remove(struct pci_dev *pdev); static void arcmsr_shutdown(struct pci_dev *pdev); static void arcmsr_iop_init(struct AdapterControlBlock *acb); static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb); +static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb); static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb); -static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb); -static uint8_t arcmsr_wait_msgint_ready(struct AdapterControlBlock *acb); +static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb); +static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb); static const char *arcmsr_info(struct Scsi_Host *); static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb); static pci_ers_result_t arcmsr_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state); static pci_ers_result_t arcmsr_pci_slot_reset(struct pci_dev *pdev); -static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev, int queue_depth) +static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev, + int queue_depth) { if (queue_depth > ARCMSR_MAX_CMD_PERLUN) queue_depth = ARCMSR_MAX_CMD_PERLUN; @@ -123,17 +127,21 @@ static struct scsi_host_template arcmsr_scsi_host_template = { .use_clustering = ENABLE_CLUSTERING, .shost_attrs = arcmsr_host_attrs, }; +#ifdef CONFIG_SCSI_ARCMSR_AER static struct pci_error_handlers arcmsr_pci_error_handlers = { .error_detected = arcmsr_pci_error_detected, .slot_reset = arcmsr_pci_slot_reset, }; - +#endif static struct pci_device_id arcmsr_device_id_table[] = { {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1110)}, {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1120)}, {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1130)}, {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1160)}, {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1170)}, + {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1200)}, + {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1201)}, + {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1202)}, {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1210)}, {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1220)}, {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1230)}, @@ -153,20 +161,20 @@ static struct pci_driver arcmsr_pci_driver = { .probe = arcmsr_probe, .remove = arcmsr_remove, .shutdown = arcmsr_shutdown, + #ifdef CONFIG_SCSI_ARCMSR_AER .err_handler = &arcmsr_pci_error_handlers, + #endif }; static irqreturn_t arcmsr_do_interrupt(int irq, void *dev_id) { irqreturn_t handle_state; - struct AdapterControlBlock *acb; - unsigned long flags; - - acb = (struct AdapterControlBlock *)dev_id; + struct AdapterControlBlock *acb = dev_id; - spin_lock_irqsave(acb->host->host_lock, flags); + spin_lock(acb->host->host_lock); handle_state = arcmsr_interrupt(acb); - spin_unlock_irqrestore(acb->host->host_lock, flags); + spin_unlock(acb->host->host_lock); + return handle_state; } @@ -198,68 +206,159 @@ static int arcmsr_bios_param(struct scsi_device *sdev, return 0; } -static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb) +static void arcmsr_define_adapter_type(struct AdapterControlBlock *acb) { struct pci_dev *pdev = acb->pdev; - struct MessageUnit __iomem *reg = acb->pmu; - u32 ccb_phyaddr_hi32; - void *dma_coherent; - dma_addr_t dma_coherent_handle, dma_addr; - struct CommandControlBlock *ccb_tmp; - int i, j; + u16 dev_id; + pci_read_config_word(pdev, PCI_DEVICE_ID, &dev_id); + switch (dev_id) { + case 0x1201 : { + acb->adapter_type = ACB_ADAPTER_TYPE_B; + } + break; + + default : acb->adapter_type = ACB_ADAPTER_TYPE_A; + } +} + +static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb) +{ + + switch (acb->adapter_type) { - dma_coherent = dma_alloc_coherent(&pdev->dev, + case ACB_ADAPTER_TYPE_A: { + struct pci_dev *pdev = acb->pdev; + void *dma_coherent; + dma_addr_t dma_coherent_handle, dma_addr; + struct CommandControlBlock *ccb_tmp; + uint32_t intmask_org; + int i, j; + + acb->pmu = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); + if (!acb->pmu) { + printk(KERN_NOTICE "arcmsr%d: memory mapping region fail \n", + acb->host->host_no); + } + + dma_coherent = dma_alloc_coherent(&pdev->dev, ARCMSR_MAX_FREECCB_NUM * sizeof (struct CommandControlBlock) + 0x20, &dma_coherent_handle, GFP_KERNEL); - if (!dma_coherent) - return -ENOMEM; + if (!dma_coherent) + return -ENOMEM; - acb->dma_coherent = dma_coherent; - acb->dma_coherent_handle = dma_coherent_handle; + acb->dma_coherent = dma_coherent; + acb->dma_coherent_handle = dma_coherent_handle; - if (((unsigned long)dma_coherent & 0x1F)) { - dma_coherent = dma_coherent + - (0x20 - ((unsigned long)dma_coherent & 0x1F)); - dma_coherent_handle = dma_coherent_handle + - (0x20 - ((unsigned long)dma_coherent_handle & 0x1F)); - } + if (((unsigned long)dma_coherent & 0x1F)) { + dma_coherent = dma_coherent + + (0x20 - ((unsigned long)dma_coherent & 0x1F)); + dma_coherent_handle = dma_coherent_handle + + (0x20 - ((unsigned long)dma_coherent_handle & 0x1F)); + } - dma_addr = dma_coherent_handle; - ccb_tmp = (struct CommandControlBlock *)dma_coherent; - for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { - ccb_tmp->cdb_shifted_phyaddr = dma_addr >> 5; - ccb_tmp->acb = acb; - acb->pccb_pool[i] = ccb_tmp; - list_add_tail(&ccb_tmp->list, &acb->ccb_free_list); - dma_addr = dma_addr + sizeof (struct CommandControlBlock); - ccb_tmp++; - } + dma_addr = dma_coherent_handle; + ccb_tmp = (struct CommandControlBlock *)dma_coherent; + for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { + ccb_tmp->cdb_shifted_phyaddr = dma_addr >> 5; + ccb_tmp->acb = acb; + acb->pccb_pool[i] = ccb_tmp; + list_add_tail(&ccb_tmp->list, &acb->ccb_free_list); + dma_addr = dma_addr + sizeof(struct CommandControlBlock); + ccb_tmp++; + } - acb->vir2phy_offset = (unsigned long)ccb_tmp - - (unsigned long)dma_addr; - for (i = 0; i < ARCMSR_MAX_TARGETID; i++) - for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++) - acb->devstate[i][j] = ARECA_RAID_GOOD; + acb->vir2phy_offset = (unsigned long)ccb_tmp -(unsigned long)dma_addr; + for (i = 0; i < ARCMSR_MAX_TARGETID; i++) + for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++) + acb->devstate[i][j] = ARECA_RAID_GONE; - /* - ** here we need to tell iop 331 our ccb_tmp.HighPart - ** if ccb_tmp.HighPart is not zero - */ - ccb_phyaddr_hi32 = (uint32_t) ((dma_coherent_handle >> 16) >> 16); - if (ccb_phyaddr_hi32 != 0) { - writel(ARCMSR_SIGNATURE_SET_CONFIG, ®->message_rwbuffer[0]); - writel(ccb_phyaddr_hi32, ®->message_rwbuffer[1]); - writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, ®->inbound_msgaddr0); - if (arcmsr_wait_msgint_ready(acb)) - printk(KERN_NOTICE "arcmsr%d: " - "'set ccb high part physical address' timeout\n", - acb->host->host_no); - } + /* + ** here we need to tell iop 331 our ccb_tmp.HighPart + ** if ccb_tmp.HighPart is not zero + */ + intmask_org = arcmsr_disable_outbound_ints(acb); + } + break; + + case ACB_ADAPTER_TYPE_B: { + + struct pci_dev *pdev = acb->pdev; + struct MessageUnit_B *reg; + void *mem_base0, *mem_base1; + void *dma_coherent; + dma_addr_t dma_coherent_handle, dma_addr; + uint32_t intmask_org; + struct CommandControlBlock *ccb_tmp; + int i, j; + + dma_coherent = dma_alloc_coherent(&pdev->dev, + ((ARCMSR_MAX_FREECCB_NUM * + sizeof(struct CommandControlBlock) + 0x20) + + sizeof(struct MessageUnit_B)), + &dma_coherent_handle, GFP_KERNEL); + if (!dma_coherent) + return -ENOMEM; + + acb->dma_coherent = dma_coherent; + acb->dma_coherent_handle = dma_coherent_handle; + + if (((unsigned long)dma_coherent & 0x1F)) { + dma_coherent = dma_coherent + + (0x20 - ((unsigned long)dma_coherent & 0x1F)); + dma_coherent_handle = dma_coherent_handle + + (0x20 - ((unsigned long)dma_coherent_handle & 0x1F)); + } + + reg = (struct MessageUnit_B *)(dma_coherent + + ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock)); + + dma_addr = dma_coherent_handle; + ccb_tmp = (struct CommandControlBlock *)dma_coherent; + for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { + ccb_tmp->cdb_shifted_phyaddr = dma_addr >> 5; + ccb_tmp->acb = acb; + acb->pccb_pool[i] = ccb_tmp; + list_add_tail(&ccb_tmp->list, &acb->ccb_free_list); + dma_addr = dma_addr + sizeof(struct CommandControlBlock); + ccb_tmp++; + } + + reg = (struct MessageUnit_B *)(dma_coherent + + ARCMSR_MAX_FREECCB_NUM * sizeof(struct CommandControlBlock)); + acb->pmu = (struct MessageUnit_B *)reg; + mem_base0 = ioremap(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0)); + mem_base1 = ioremap(pci_resource_start(pdev, 2), + pci_resource_len(pdev, 2)); + reg->drv2iop_doorbell_reg = (uint32_t *)((char *)mem_base0 + + ARCMSR_DRV2IOP_DOORBELL); + reg->drv2iop_doorbell_mask_reg = (uint32_t *)((char *)mem_base0 + + ARCMSR_DRV2IOP_DOORBELL_MASK); + reg->iop2drv_doorbell_reg = (uint32_t *)((char *)mem_base0 + + ARCMSR_IOP2DRV_DOORBELL); + reg->iop2drv_doorbell_mask_reg = (uint32_t *)((char *)mem_base0 + + ARCMSR_IOP2DRV_DOORBELL_MASK); + reg->ioctl_wbuffer_reg = (uint32_t *)((char *)mem_base1 + + ARCMSR_IOCTL_WBUFFER); + reg->ioctl_rbuffer_reg = (uint32_t *)((char *)mem_base1 + + ARCMSR_IOCTL_RBUFFER); + reg->msgcode_rwbuffer_reg = (uint32_t *)((char *)mem_base1 + + ARCMSR_MSGCODE_RWBUFFER); + + acb->vir2phy_offset = (unsigned long)ccb_tmp -(unsigned long)dma_addr; + for (i = 0; i < ARCMSR_MAX_TARGETID; i++) + for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++) + acb->devstate[i][j] = ARECA_RAID_GOOD; - writel(readl(®->outbound_intmask) | - ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE, - ®->outbound_intmask); + /* + ** here we need to tell iop 331 our ccb_tmp.HighPart + ** if ccb_tmp.HighPart is not zero + */ + intmask_org = arcmsr_disable_outbound_ints(acb); + } + break; + } return 0; } @@ -310,16 +409,11 @@ static int arcmsr_probe(struct pci_dev *pdev, host->unique_id = (bus << 8) | dev_fun; host->irq = pdev->irq; error = pci_request_regions(pdev, "arcmsr"); - if (error) + if (error) { goto out_host_put; - - acb->pmu = ioremap(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0)); - if (!acb->pmu) { - printk(KERN_NOTICE "arcmsr%d: memory" - " mapping region fail \n", acb->host->host_no); - goto out_release_regions; } + arcmsr_define_adapter_type(acb); + acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED | ACB_F_MESSAGE_RQBUFFER_CLEARED | ACB_F_MESSAGE_WQBUFFER_READED); @@ -328,10 +422,10 @@ static int arcmsr_probe(struct pci_dev *pdev, error = arcmsr_alloc_ccb_pool(acb); if (error) - goto out_iounmap; + goto out_release_regions; error = request_irq(pdev->irq, arcmsr_do_interrupt, - IRQF_DISABLED | IRQF_SHARED, "arcmsr", acb); + IRQF_SHARED, "arcmsr", acb); if (error) goto out_free_ccb_pool; @@ -349,14 +443,15 @@ static int arcmsr_probe(struct pci_dev *pdev, goto out_free_sysfs; scsi_scan_host(host); + #ifdef CONFIG_SCSI_ARCMSR_AER pci_enable_pcie_error_reporting(pdev); + #endif return 0; out_free_sysfs: out_free_irq: free_irq(pdev->irq, acb); out_free_ccb_pool: arcmsr_free_ccb_pool(acb); - out_iounmap: iounmap(acb->pmu); out_release_regions: pci_release_regions(pdev); @@ -368,17 +463,84 @@ static int arcmsr_probe(struct pci_dev *pdev, return error; } -static void arcmsr_abort_allcmd(struct AdapterControlBlock *acb) +static uint8_t arcmsr_hba_wait_msgint_ready(struct AdapterControlBlock *acb) +{ + struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu; + uint32_t Index; + uint8_t Retries = 0x00; + + do { + for (Index = 0; Index < 100; Index++) { + if (readl(®->outbound_intstatus) & + ARCMSR_MU_OUTBOUND_MESSAGE0_INT) { + writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT, + ®->outbound_intstatus); + return 0x00; + } + msleep(10); + }/*max 1 seconds*/ + + } while (Retries++ < 20);/*max 20 sec*/ + return 0xff; +} + +static uint8_t arcmsr_hbb_wait_msgint_ready(struct AdapterControlBlock *acb) +{ + struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu; + uint32_t Index; + uint8_t Retries = 0x00; + + do { + for (Index = 0; Index < 100; Index++) { + if (readl(reg->iop2drv_doorbell_reg) + & ARCMSR_IOP2DRV_MESSAGE_CMD_DONE) { + writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN + , reg->iop2drv_doorbell_reg); + return 0x00; + } + msleep(10); + }/*max 1 seconds*/ + + } while (Retries++ < 20);/*max 20 sec*/ + return 0xff; +} + +static void arcmsr_abort_hba_allcmd(struct AdapterControlBlock *acb) { - struct MessageUnit __iomem *reg = acb->pmu; + struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu; writel(ARCMSR_INBOUND_MESG0_ABORT_CMD, ®->inbound_msgaddr0); - if (arcmsr_wait_msgint_ready(acb)) + if (arcmsr_hba_wait_msgint_ready(acb)) + printk(KERN_NOTICE + "arcmsr%d: wait 'abort all outstanding command' timeout \n" + , acb->host->host_no); +} + +static void arcmsr_abort_hbb_allcmd(struct AdapterControlBlock *acb) +{ + struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu; + + writel(ARCMSR_MESSAGE_ABORT_CMD, reg->drv2iop_doorbell_reg); + if (arcmsr_hbb_wait_msgint_ready(acb)) printk(KERN_NOTICE "arcmsr%d: wait 'abort all outstanding command' timeout \n" , acb->host->host_no); } +static void arcmsr_abort_allcmd(struct AdapterControlBlock *acb) +{ + switch (acb->adapter_type) { + case ACB_ADAPTER_TYPE_A: { + arcmsr_abort_hba_allcmd(acb); + } + break; + + case ACB_ADAPTER_TYPE_B: { + arcmsr_abort_hbb_allcmd(acb); + } + } +} + static void arcmsr_pci_unmap_dma(struct CommandControlBlock *ccb) { struct scsi_cmnd *pcmd = ccb->pcmd; @@ -400,28 +562,239 @@ static void arcmsr_ccb_complete(struct CommandControlBlock *ccb, int stand_flag) pcmd->scsi_done(pcmd); } +static void arcmsr_flush_hba_cache(struct AdapterControlBlock *acb) +{ + struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu; + int retry_count = 30; + + writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, ®->inbound_msgaddr0); + do { + if (!arcmsr_hba_wait_msgint_ready(acb)) + break; + else { + retry_count--; + printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \ + timeout, retry count down = %d \n", acb->host->host_no, retry_count); + } + } while (retry_count != 0); +} + +static void arcmsr_flush_hbb_cache(struct AdapterControlBlock *acb) +{ + struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu; + int retry_count = 30; + + writel(ARCMSR_MESSAGE_FLUSH_CACHE, reg->drv2iop_doorbell_reg); + do { + if (!arcmsr_hbb_wait_msgint_ready(acb)) + break; + else { + retry_count--; + printk(KERN_NOTICE "arcmsr%d: wait 'flush adapter cache' \ + timeout,retry count down = %d \n", acb->host->host_no, retry_count); + } + } while (retry_count != 0); +} + +static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb) +{ + switch (acb->adapter_type) { + + case ACB_ADAPTER_TYPE_A: { + arcmsr_flush_hba_cache(acb); + } + break; + + case ACB_ADAPTER_TYPE_B: { + arcmsr_flush_hbb_cache(acb); + } + } +} + +static void arcmsr_report_sense_info(struct CommandControlBlock *ccb) +{ + + struct scsi_cmnd *pcmd = ccb->pcmd; + struct SENSE_DATA *sensebuffer = (struct SENSE_DATA *)pcmd->sense_buffer; + + pcmd->result = DID_OK << 16; + if (sensebuffer) { + int sense_data_length = + sizeof(struct SENSE_DATA) < sizeof(pcmd->sense_buffer) + ? sizeof(struct SENSE_DATA) : sizeof(pcmd->sense_buffer); + memset(sensebuffer, 0, sizeof(pcmd->sense_buffer)); + memcpy(sensebuffer, ccb->arcmsr_cdb.SenseData, sense_data_length); + sensebuffer->ErrorCode = SCSI_SENSE_CURRENT_ERRORS; + sensebuffer->Valid = 1; + } +} + +static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb) +{ + u32 orig_mask = 0; + switch (acb->adapter_type) { + + case ACB_ADAPTER_TYPE_A : { + struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu; + orig_mask = readl(®->outbound_intmask)|\ + ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE; + writel(orig_mask|ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE, \ + ®->outbound_intmask); + } + break; + + case ACB_ADAPTER_TYPE_B : { + struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu; + orig_mask = readl(reg->iop2drv_doorbell_mask_reg) & \ + (~ARCMSR_IOP2DRV_MESSAGE_CMD_DONE); + writel(0, reg->iop2drv_doorbell_mask_reg); + } + break; + } + return orig_mask; +} + +static void arcmsr_report_ccb_state(struct AdapterControlBlock *acb, \ + struct CommandControlBlock *ccb, uint32_t flag_ccb) +{ + + uint8_t id, lun; + id = ccb->pcmd->device->id; + lun = ccb->pcmd->device->lun; + if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) { + if (acb->devstate[id][lun] == ARECA_RAID_GONE) + acb->devstate[id][lun] = ARECA_RAID_GOOD; + ccb->pcmd->result = DID_OK << 16; + arcmsr_ccb_complete(ccb, 1); + } else { + switch (ccb->arcmsr_cdb.DeviceStatus) { + case ARCMSR_DEV_SELECT_TIMEOUT: { + acb->devstate[id][lun] = ARECA_RAID_GONE; + ccb->pcmd->result = DID_NO_CONNECT << 16; + arcmsr_ccb_complete(ccb, 1); + } + break; + + case ARCMSR_DEV_ABORTED: + + case ARCMSR_DEV_INIT_FAIL: { + acb->devstate[id][lun] = ARECA_RAID_GONE; + ccb->pcmd->result = DID_BAD_TARGET << 16; + arcmsr_ccb_complete(ccb, 1); + } + break; + + case ARCMSR_DEV_CHECK_CONDITION: { + acb->devstate[id][lun] = ARECA_RAID_GOOD; + arcmsr_report_sense_info(ccb); + arcmsr_ccb_complete(ccb, 1); + } + break; + + default: + printk(KERN_NOTICE + "arcmsr%d: scsi id = %d lun = %d" + " isr get command error done, " + "but got unknown DeviceStatus = 0x%x \n" + , acb->host->host_no + , id + , lun + , ccb->arcmsr_cdb.DeviceStatus); + acb->devstate[id][lun] = ARECA_RAID_GONE; + ccb->pcmd->result = DID_NO_CONNECT << 16; + arcmsr_ccb_complete(ccb, 1); + break; + } + } +} + +static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, uint32_t flag_ccb) + +{ + struct CommandControlBlock *ccb; + + ccb = (struct CommandControlBlock *)(acb->vir2phy_offset + (flag_ccb << 5)); + if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) { + if (ccb->startdone == ARCMSR_CCB_ABORTED) { + struct scsi_cmnd *abortcmd = ccb->pcmd; + if (abortcmd) { + abortcmd->result |= DID_ABORT << 16; + arcmsr_ccb_complete(ccb, 1); + printk(KERN_NOTICE "arcmsr%d: ccb ='0x%p' \ + isr got aborted command \n", acb->host->host_no, ccb); + } + } + printk(KERN_NOTICE "arcmsr%d: isr get an illegal ccb command \ + done acb = '0x%p'" + "ccb = '0x%p' ccbacb = '0x%p' startdone = 0x%x" + " ccboutstandingcount = %d \n" + , acb->host->host_no + , acb + , ccb + , ccb->acb + , ccb->startdone + , atomic_read(&acb->ccboutstandingcount)); + } + arcmsr_report_ccb_state(acb, ccb, flag_ccb); +} + +static void arcmsr_done4abort_postqueue(struct AdapterControlBlock *acb) +{ + int i = 0; + uint32_t flag_ccb; + + switch (acb->adapter_type) { + + case ACB_ADAPTER_TYPE_A: { + struct MessageUnit_A __iomem *reg = \ + (struct MessageUnit_A *)acb->pmu; + uint32_t outbound_intstatus; + outbound_intstatus = readl(®->outbound_intstatus) & \ + acb->outbound_int_enable; + /*clear and abort all outbound posted Q*/ + writel(outbound_intstatus, ®->outbound_intstatus);/*clear interrupt*/ + while (((flag_ccb = readl(®->outbound_queueport)) != 0xFFFFFFFF) \ + && (i++ < ARCMSR_MAX_OUTSTANDING_CMD)) { + arcmsr_drain_donequeue(acb, flag_ccb); + } + } + break; + + case ACB_ADAPTER_TYPE_B: { + struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu; + /*clear all outbound posted Q*/ + for (i = 0; i < ARCMSR_MAX_HBB_POSTQUEUE; i++) { + if ((flag_ccb = readl(®->done_qbuffer[i])) != 0) { + writel(0, ®->done_qbuffer[i]); + arcmsr_drain_donequeue(acb, flag_ccb); + } + writel(0, ®->post_qbuffer[i]); + } + reg->doneq_index = 0; + reg->postq_index = 0; + } + break; + } +} static void arcmsr_remove(struct pci_dev *pdev) { struct Scsi_Host *host = pci_get_drvdata(pdev); struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; - struct MessageUnit __iomem *reg = acb->pmu; int poll_count = 0; arcmsr_free_sysfs_attr(acb); scsi_remove_host(host); arcmsr_stop_adapter_bgrb(acb); arcmsr_flush_adapter_cache(acb); - writel(readl(®->outbound_intmask) | - ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE, - ®->outbound_intmask); + arcmsr_disable_outbound_ints(acb); acb->acb_flags |= ACB_F_SCSISTOPADAPTER; acb->acb_flags &= ~ACB_F_IOP_INITED; - for (poll_count = 0; poll_count < 256; poll_count++) { + for (poll_count = 0; poll_count < ARCMSR_MAX_OUTSTANDING_CMD; poll_count++) { if (!atomic_read(&acb->ccboutstandingcount)) break; - arcmsr_interrupt(acb); + arcmsr_interrupt(acb);/* FIXME: need spinlock */ msleep(25); } @@ -429,8 +802,7 @@ static void arcmsr_remove(struct pci_dev *pdev) int i; arcmsr_abort_allcmd(acb); - for (i = 0; i < ARCMSR_MAX_OUTSTANDING_CMD; i++) - readl(®->outbound_queueport); + arcmsr_done4abort_postqueue(acb); for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { struct CommandControlBlock *ccb = acb->pccb_pool[i]; if (ccb->startdone == ARCMSR_CCB_START) { @@ -477,86 +849,43 @@ static void arcmsr_module_exit(void) module_init(arcmsr_module_init); module_exit(arcmsr_module_exit); -static u32 arcmsr_disable_outbound_ints(struct AdapterControlBlock *acb) -{ - struct MessageUnit __iomem *reg = acb->pmu; - u32 orig_mask = readl(®->outbound_intmask); - - writel(orig_mask | ARCMSR_MU_OUTBOUND_ALL_INTMASKENABLE, - ®->outbound_intmask); - return orig_mask; -} - -static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb, - u32 orig_mask) +static void arcmsr_enable_outbound_ints(struct AdapterControlBlock *acb, \ + u32 intmask_org) { - struct MessageUnit __iomem *reg = acb->pmu; u32 mask; - mask = orig_mask & ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE | - ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE); - writel(mask, ®->outbound_intmask); -} - -static void arcmsr_flush_adapter_cache(struct AdapterControlBlock *acb) -{ - struct MessageUnit __iomem *reg = acb->pmu; - - writel(ARCMSR_INBOUND_MESG0_FLUSH_CACHE, ®->inbound_msgaddr0); - if (arcmsr_wait_msgint_ready(acb)) - printk(KERN_NOTICE - "arcmsr%d: wait 'flush adapter cache' timeout \n" - , acb->host->host_no); -} + switch (acb->adapter_type) { -static void arcmsr_report_sense_info(struct CommandControlBlock *ccb) -{ - struct scsi_cmnd *pcmd = ccb->pcmd; - struct SENSE_DATA *sensebuffer = (struct SENSE_DATA *)pcmd->sense_buffer; + case ACB_ADAPTER_TYPE_A : { + struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu; + mask = intmask_org & ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE | + ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE); + writel(mask, ®->outbound_intmask); + acb->outbound_int_enable = ~(intmask_org & mask) & 0x000000ff; + } + break; - pcmd->result = DID_OK << 16; - if (sensebuffer) { - int sense_data_length = - sizeof (struct SENSE_DATA) < sizeof (pcmd->sense_buffer) - ? sizeof (struct SENSE_DATA) : sizeof (pcmd->sense_buffer); - memset(sensebuffer, 0, sizeof (pcmd->sense_buffer)); - memcpy(sensebuffer, ccb->arcmsr_cdb.SenseData, sense_data_length); - sensebuffer->ErrorCode = SCSI_SENSE_CURRENT_ERRORS; - sensebuffer->Valid = 1; + case ACB_ADAPTER_TYPE_B : { + struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu; + mask = intmask_org | (ARCMSR_IOP2DRV_DATA_WRITE_OK | \ + ARCMSR_IOP2DRV_DATA_READ_OK | ARCMSR_IOP2DRV_CDB_DONE); + writel(mask, reg->iop2drv_doorbell_mask_reg); + acb->outbound_int_enable = (intmask_org | mask) & 0x0000000f; + } } } -static uint8_t arcmsr_wait_msgint_ready(struct AdapterControlBlock *acb) +static void arcmsr_build_ccb(struct AdapterControlBlock *acb, + struct CommandControlBlock *ccb, struct scsi_cmnd *pcmd) { - struct MessageUnit __iomem *reg = acb->pmu; - uint32_t Index; - uint8_t Retries = 0x00; - - do { - for (Index = 0; Index < 100; Index++) { - if (readl(®->outbound_intstatus) - & ARCMSR_MU_OUTBOUND_MESSAGE0_INT) { - writel(ARCMSR_MU_OUTBOUND_MESSAGE0_INT - , ®->outbound_intstatus); - return 0x00; - } - msleep_interruptible(10); - }/*max 1 seconds*/ - } while (Retries++ < 20);/*max 20 sec*/ - return 0xff; -} - -static void arcmsr_build_ccb(struct AdapterControlBlock *acb, - struct CommandControlBlock *ccb, struct scsi_cmnd *pcmd) -{ - struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb; - int8_t *psge = (int8_t *)&arcmsr_cdb->u; - uint32_t address_lo, address_hi; - int arccdbsize = 0x30; - int nseg; + struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb; + int8_t *psge = (int8_t *)&arcmsr_cdb->u; + uint32_t address_lo, address_hi; + int arccdbsize = 0x30; + int nseg; ccb->pcmd = pcmd; - memset(arcmsr_cdb, 0, sizeof (struct ARCMSR_CDB)); + memset(arcmsr_cdb, 0, sizeof(struct ARCMSR_CDB)); arcmsr_cdb->Bus = 0; arcmsr_cdb->TargetID = pcmd->device->id; arcmsr_cdb->LUN = pcmd->device->lun; @@ -609,52 +938,85 @@ static void arcmsr_build_ccb(struct AdapterControlBlock *acb, static void arcmsr_post_ccb(struct AdapterControlBlock *acb, struct CommandControlBlock *ccb) { - struct MessageUnit __iomem *reg = acb->pmu; uint32_t cdb_shifted_phyaddr = ccb->cdb_shifted_phyaddr; struct ARCMSR_CDB *arcmsr_cdb = (struct ARCMSR_CDB *)&ccb->arcmsr_cdb; - atomic_inc(&acb->ccboutstandingcount); ccb->startdone = ARCMSR_CCB_START; - if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) - writel(cdb_shifted_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE, + + switch (acb->adapter_type) { + case ACB_ADAPTER_TYPE_A: { + struct MessageUnit_A *reg = (struct MessageUnit_A *)acb->pmu; + + if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) + writel(cdb_shifted_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE, ®->inbound_queueport); - else - writel(cdb_shifted_phyaddr, ®->inbound_queueport); -} + else { + writel(cdb_shifted_phyaddr, ®->inbound_queueport); + } + } + break; -void arcmsr_post_Qbuffer(struct AdapterControlBlock *acb) -{ - struct MessageUnit __iomem *reg = acb->pmu; - struct QBUFFER __iomem *pwbuffer = (struct QBUFFER __iomem *) ®->message_wbuffer; - uint8_t __iomem *iop_data = (uint8_t __iomem *) pwbuffer->data; - int32_t allxfer_len = 0; + case ACB_ADAPTER_TYPE_B: { + struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu; + uint32_t ending_index, index = reg->postq_index; - if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_READED) { - acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED); - while ((acb->wqbuf_firstindex != acb->wqbuf_lastindex) - && (allxfer_len < 124)) { - writeb(acb->wqbuffer[acb->wqbuf_firstindex], iop_data); - acb->wqbuf_firstindex++; - acb->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER; - iop_data++; - allxfer_len++; + ending_index = ((index + 1) % ARCMSR_MAX_HBB_POSTQUEUE); + writel(0, ®->post_qbuffer[ending_index]); + if (arcmsr_cdb->Flags & ARCMSR_CDB_FLAG_SGL_BSIZE) { + writel(cdb_shifted_phyaddr | ARCMSR_CCBPOST_FLAG_SGL_BSIZE,\ + ®->post_qbuffer[index]); + } + else { + writel(cdb_shifted_phyaddr, ®->post_qbuffer[index]); + } + index++; + index %= ARCMSR_MAX_HBB_POSTQUEUE;/*if last index number set it to 0 */ + reg->postq_index = index; + writel(ARCMSR_DRV2IOP_CDB_POSTED, reg->drv2iop_doorbell_reg); } - writel(allxfer_len, &pwbuffer->data_len); - writel(ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK - , ®->inbound_doorbell); + break; } } -static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb) +static void arcmsr_stop_hba_bgrb(struct AdapterControlBlock *acb) { - struct MessageUnit __iomem *reg = acb->pmu; - + struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu; acb->acb_flags &= ~ACB_F_MSG_START_BGRB; writel(ARCMSR_INBOUND_MESG0_STOP_BGRB, ®->inbound_msgaddr0); - if (arcmsr_wait_msgint_ready(acb)) + + if (arcmsr_hba_wait_msgint_ready(acb)) { + printk(KERN_NOTICE + "arcmsr%d: wait 'stop adapter background rebulid' timeout \n" + , acb->host->host_no); + } +} + +static void arcmsr_stop_hbb_bgrb(struct AdapterControlBlock *acb) +{ + struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu; + acb->acb_flags &= ~ACB_F_MSG_START_BGRB; + writel(ARCMSR_MESSAGE_STOP_BGRB, reg->drv2iop_doorbell_reg); + + if (arcmsr_hbb_wait_msgint_ready(acb)) { printk(KERN_NOTICE "arcmsr%d: wait 'stop adapter background rebulid' timeout \n" , acb->host->host_no); + } +} + +static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb) +{ + switch (acb->adapter_type) { + case ACB_ADAPTER_TYPE_A: { + arcmsr_stop_hba_bgrb(acb); + } + break; + + case ACB_ADAPTER_TYPE_B: { + arcmsr_stop_hbb_bgrb(acb); + } + break; + } } static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb) @@ -665,151 +1027,260 @@ static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb) acb->dma_coherent_handle); } -static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb) +void arcmsr_iop_message_read(struct AdapterControlBlock *acb) { - struct MessageUnit __iomem *reg = acb->pmu; - struct CommandControlBlock *ccb; - uint32_t flag_ccb, outbound_intstatus, outbound_doorbell; + switch (acb->adapter_type) { + case ACB_ADAPTER_TYPE_A: { + struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu; + writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, ®->inbound_doorbell); + } + break; - outbound_intstatus = readl(®->outbound_intstatus) - & acb->outbound_int_enable; - writel(outbound_intstatus, ®->outbound_intstatus); - if (outbound_intstatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT) { - outbound_doorbell = readl(®->outbound_doorbell); - writel(outbound_doorbell, ®->outbound_doorbell); - if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK) { - struct QBUFFER __iomem * prbuffer = - (struct QBUFFER __iomem *) ®->message_rbuffer; - uint8_t __iomem * iop_data = (uint8_t __iomem *)prbuffer->data; - int32_t my_empty_len, iop_len, rqbuf_firstindex, rqbuf_lastindex; - - rqbuf_lastindex = acb->rqbuf_lastindex; - rqbuf_firstindex = acb->rqbuf_firstindex; - iop_len = readl(&prbuffer->data_len); - my_empty_len = (rqbuf_firstindex - rqbuf_lastindex - 1) - &(ARCMSR_MAX_QBUFFER - 1); - if (my_empty_len >= iop_len) { - while (iop_len > 0) { - acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data); - acb->rqbuf_lastindex++; - acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER; - iop_data++; - iop_len--; - } - writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, - ®->inbound_doorbell); - } else - acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW; - } - if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK) { - acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_READED; - if (acb->wqbuf_firstindex != acb->wqbuf_lastindex) { - struct QBUFFER __iomem * pwbuffer = - (struct QBUFFER __iomem *) ®->message_wbuffer; - uint8_t __iomem * iop_data = (uint8_t __iomem *) pwbuffer->data; - int32_t allxfer_len = 0; - - acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED); - while ((acb->wqbuf_firstindex != acb->wqbuf_lastindex) - && (allxfer_len < 124)) { - writeb(acb->wqbuffer[acb->wqbuf_firstindex], iop_data); - acb->wqbuf_firstindex++; - acb->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER; - iop_data++; - allxfer_len++; - } - writel(allxfer_len, &pwbuffer->data_len); - writel(ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK, - ®->inbound_doorbell); - } - if (acb->wqbuf_firstindex == acb->wqbuf_lastindex) - acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_CLEARED; + case ACB_ADAPTER_TYPE_B: { + struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu; + writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell_reg); } + break; } - if (outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT) { - int id, lun; +} + +static void arcmsr_iop_message_wrote(struct AdapterControlBlock *acb) +{ + switch (acb->adapter_type) { + case ACB_ADAPTER_TYPE_A: { + struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu; /* - **************************************************************** - ** areca cdb command done - **************************************************************** + ** push inbound doorbell tell iop, driver data write ok + ** and wait reply on next hwinterrupt for next Qbuffer post */ - while (1) { - if ((flag_ccb = readl(®->outbound_queueport)) == 0xFFFFFFFF) - break;/*chip FIFO no ccb for completion already*/ - /* check if command done with no error*/ - ccb = (struct CommandControlBlock *)(acb->vir2phy_offset + - (flag_ccb << 5)); - if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) { - if (ccb->startdone == ARCMSR_CCB_ABORTED) { - struct scsi_cmnd *abortcmd = ccb->pcmd; - if (abortcmd) { - abortcmd->result |= DID_ABORT >> 16; - arcmsr_ccb_complete(ccb, 1); - printk(KERN_NOTICE - "arcmsr%d: ccb ='0x%p' isr got aborted command \n" - , acb->host->host_no, ccb); - } - continue; - } - printk(KERN_NOTICE - "arcmsr%d: isr get an illegal ccb command done acb = '0x%p'" - "ccb = '0x%p' ccbacb = '0x%p' startdone = 0x%x" - " ccboutstandingcount = %d \n" - , acb->host->host_no - , acb - , ccb - , ccb->acb - , ccb->startdone - , atomic_read(&acb->ccboutstandingcount)); - continue; - } - id = ccb->pcmd->device->id; - lun = ccb->pcmd->device->lun; - if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) { - if (acb->devstate[id][lun] == ARECA_RAID_GONE) - acb->devstate[id][lun] = ARECA_RAID_GOOD; - ccb->pcmd->result = DID_OK << 16; - arcmsr_ccb_complete(ccb, 1); - } else { - switch(ccb->arcmsr_cdb.DeviceStatus) { - case ARCMSR_DEV_SELECT_TIMEOUT: { - acb->devstate[id][lun] = ARECA_RAID_GONE; - ccb->pcmd->result = DID_NO_CONNECT << 16; - arcmsr_ccb_complete(ccb, 1); - } - break; - case ARCMSR_DEV_ABORTED: - case ARCMSR_DEV_INIT_FAIL: { - acb->devstate[id][lun] = ARECA_RAID_GONE; - ccb->pcmd->result = DID_BAD_TARGET << 16; - arcmsr_ccb_complete(ccb, 1); - } - break; - case ARCMSR_DEV_CHECK_CONDITION: { - acb->devstate[id][lun] = ARECA_RAID_GOOD; - arcmsr_report_sense_info(ccb); - arcmsr_ccb_complete(ccb, 1); - } - break; - default: - printk(KERN_NOTICE - "arcmsr%d: scsi id = %d lun = %d" - " isr get command error done, " - "but got unknown DeviceStatus = 0x%x \n" - , acb->host->host_no - , id - , lun - , ccb->arcmsr_cdb.DeviceStatus); - acb->devstate[id][lun] = ARECA_RAID_GONE; - ccb->pcmd->result = DID_NO_CONNECT << 16; - arcmsr_ccb_complete(ccb, 1); - break; - } - } - }/*drain reply FIFO*/ + writel(ARCMSR_INBOUND_DRIVER_DATA_WRITE_OK, ®->inbound_doorbell); + } + break; + + case ACB_ADAPTER_TYPE_B: { + struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu; + /* + ** push inbound doorbell tell iop, driver data write ok + ** and wait reply on next hwinterrupt for next Qbuffer post + */ + writel(ARCMSR_DRV2IOP_DATA_WRITE_OK, reg->drv2iop_doorbell_reg); + } + break; + } +} + +struct QBUFFER *arcmsr_get_iop_rqbuffer(struct AdapterControlBlock *acb) +{ + static struct QBUFFER *qbuffer; + + switch (acb->adapter_type) { + + case ACB_ADAPTER_TYPE_A: { + struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu; + qbuffer = (struct QBUFFER __iomem *) ®->message_rbuffer; + } + break; + + case ACB_ADAPTER_TYPE_B: { + struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu; + qbuffer = (struct QBUFFER __iomem *) reg->ioctl_rbuffer_reg; + } + break; + } + return qbuffer; +} + +static struct QBUFFER *arcmsr_get_iop_wqbuffer(struct AdapterControlBlock *acb) +{ + static struct QBUFFER *pqbuffer; + + switch (acb->adapter_type) { + + case ACB_ADAPTER_TYPE_A: { + struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu; + pqbuffer = (struct QBUFFER *) ®->message_wbuffer; + } + break; + + case ACB_ADAPTER_TYPE_B: { + struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu; + pqbuffer = (struct QBUFFER __iomem *)reg->ioctl_wbuffer_reg; + } + break; + } + return pqbuffer; +} + +static void arcmsr_iop2drv_data_wrote_handle(struct AdapterControlBlock *acb) +{ + struct QBUFFER *prbuffer; + struct QBUFFER *pQbuffer; + uint8_t *iop_data; + int32_t my_empty_len, iop_len, rqbuf_firstindex, rqbuf_lastindex; + + rqbuf_lastindex = acb->rqbuf_lastindex; + rqbuf_firstindex = acb->rqbuf_firstindex; + prbuffer = arcmsr_get_iop_rqbuffer(acb); + iop_data = (uint8_t *)prbuffer->data; + iop_len = prbuffer->data_len; + my_empty_len = (rqbuf_firstindex - rqbuf_lastindex -1)&(ARCMSR_MAX_QBUFFER -1); + + if (my_empty_len >= iop_len) + { + while (iop_len > 0) { + pQbuffer = (struct QBUFFER *)&acb->rqbuffer[rqbuf_lastindex]; + memcpy(pQbuffer, iop_data,1); + rqbuf_lastindex++; + rqbuf_lastindex %= ARCMSR_MAX_QBUFFER; + iop_data++; + iop_len--; + } + acb->rqbuf_lastindex = rqbuf_lastindex; + arcmsr_iop_message_read(acb); + } + + else { + acb->acb_flags |= ACB_F_IOPDATA_OVERFLOW; + } +} + +static void arcmsr_iop2drv_data_read_handle(struct AdapterControlBlock *acb) +{ + acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_READED; + if (acb->wqbuf_firstindex != acb->wqbuf_lastindex) { + uint8_t *pQbuffer; + struct QBUFFER *pwbuffer; + uint8_t *iop_data; + int32_t allxfer_len = 0; + + acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED); + pwbuffer = arcmsr_get_iop_wqbuffer(acb); + iop_data = (uint8_t __iomem *)pwbuffer->data; + + while ((acb->wqbuf_firstindex != acb->wqbuf_lastindex) && \ + (allxfer_len < 124)) { + pQbuffer = &acb->wqbuffer[acb->wqbuf_firstindex]; + memcpy(iop_data, pQbuffer, 1); + acb->wqbuf_firstindex++; + acb->wqbuf_firstindex %= ARCMSR_MAX_QBUFFER; + iop_data++; + allxfer_len++; + } + pwbuffer->data_len = allxfer_len; + + arcmsr_iop_message_wrote(acb); + } + + if (acb->wqbuf_firstindex == acb->wqbuf_lastindex) { + acb->acb_flags |= ACB_F_MESSAGE_WQBUFFER_CLEARED; + } +} + +static void arcmsr_hba_doorbell_isr(struct AdapterControlBlock *acb) +{ + uint32_t outbound_doorbell; + struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu; + + outbound_doorbell = readl(®->outbound_doorbell); + writel(outbound_doorbell, ®->outbound_doorbell); + if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_WRITE_OK) { + arcmsr_iop2drv_data_wrote_handle(acb); + } + + if (outbound_doorbell & ARCMSR_OUTBOUND_IOP331_DATA_READ_OK) { + arcmsr_iop2drv_data_read_handle(acb); + } +} + +static void arcmsr_hba_postqueue_isr(struct AdapterControlBlock *acb) +{ + uint32_t flag_ccb; + struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu; + + while ((flag_ccb = readl(®->outbound_queueport)) != 0xFFFFFFFF) { + arcmsr_drain_donequeue(acb, flag_ccb); + } +} + +static void arcmsr_hbb_postqueue_isr(struct AdapterControlBlock *acb) +{ + uint32_t index; + uint32_t flag_ccb; + struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu; + + index = reg->doneq_index; + + while ((flag_ccb = readl(®->done_qbuffer[index])) != 0) { + writel(0, ®->done_qbuffer[index]); + arcmsr_drain_donequeue(acb, flag_ccb); + index++; + index %= ARCMSR_MAX_HBB_POSTQUEUE; + reg->doneq_index = index; + } +} + +static int arcmsr_handle_hba_isr(struct AdapterControlBlock *acb) +{ + uint32_t outbound_intstatus; + struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu; + + outbound_intstatus = readl(®->outbound_intstatus) & \ + acb->outbound_int_enable; + if (!(outbound_intstatus & ARCMSR_MU_OUTBOUND_HANDLE_INT)) { + return 1; + } + writel(outbound_intstatus, ®->outbound_intstatus); + if (outbound_intstatus & ARCMSR_MU_OUTBOUND_DOORBELL_INT) { + arcmsr_hba_doorbell_isr(acb); + } + if (outbound_intstatus & ARCMSR_MU_OUTBOUND_POSTQUEUE_INT) { + arcmsr_hba_postqueue_isr(acb); + } + return 0; +} + +static int arcmsr_handle_hbb_isr(struct AdapterControlBlock *acb) +{ + uint32_t outbound_doorbell; + struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu; + + outbound_doorbell = readl(reg->iop2drv_doorbell_reg) & \ + acb->outbound_int_enable; + if (!outbound_doorbell) + return 1; + + writel(~outbound_doorbell, reg->iop2drv_doorbell_reg); + + if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_WRITE_OK) { + arcmsr_iop2drv_data_wrote_handle(acb); + } + if (outbound_doorbell & ARCMSR_IOP2DRV_DATA_READ_OK) { + arcmsr_iop2drv_data_read_handle(acb); + } + if (outbound_doorbell & ARCMSR_IOP2DRV_CDB_DONE) { + arcmsr_hbb_postqueue_isr(acb); + } + + return 0; +} + +static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb) +{ + switch (acb->adapter_type) { + case ACB_ADAPTER_TYPE_A: { + if (arcmsr_handle_hba_isr(acb)) { + return IRQ_NONE; + } + } + break; + + case ACB_ADAPTER_TYPE_B: { + if (arcmsr_handle_hbb_isr(acb)) { + return IRQ_NONE; + } + } + break; } - if (!(outbound_intstatus & ARCMSR_MU_OUTBOUND_HANDLE_INT)) - return IRQ_NONE; return IRQ_HANDLED; } @@ -818,16 +1289,47 @@ static void arcmsr_iop_parking(struct AdapterControlBlock *acb) if (acb) { /* stop adapter background rebuild */ if (acb->acb_flags & ACB_F_MSG_START_BGRB) { + uint32_t intmask_org; acb->acb_flags &= ~ACB_F_MSG_START_BGRB; + intmask_org = arcmsr_disable_outbound_ints(acb); arcmsr_stop_adapter_bgrb(acb); arcmsr_flush_adapter_cache(acb); + arcmsr_enable_outbound_ints(acb, intmask_org); + } + } +} + +void arcmsr_post_ioctldata2iop(struct AdapterControlBlock *acb) +{ + int32_t wqbuf_firstindex, wqbuf_lastindex; + uint8_t *pQbuffer; + struct QBUFFER *pwbuffer; + uint8_t *iop_data; + int32_t allxfer_len = 0; + + pwbuffer = arcmsr_get_iop_wqbuffer(acb); + iop_data = (uint8_t __iomem *)pwbuffer->data; + if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_READED) { + acb->acb_flags &= (~ACB_F_MESSAGE_WQBUFFER_READED); + wqbuf_firstindex = acb->wqbuf_firstindex; + wqbuf_lastindex = acb->wqbuf_lastindex; + while ((wqbuf_firstindex != wqbuf_lastindex) && (allxfer_len < 124)) { + pQbuffer = &acb->wqbuffer[wqbuf_firstindex]; + memcpy(iop_data, pQbuffer, 1); + wqbuf_firstindex++; + wqbuf_firstindex %= ARCMSR_MAX_QBUFFER; + iop_data++; + allxfer_len++; } + acb->wqbuf_firstindex = wqbuf_firstindex; + pwbuffer->data_len = allxfer_len; + arcmsr_iop_message_wrote(acb); } } -static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, struct scsi_cmnd *cmd) +static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, \ + struct scsi_cmnd *cmd) { - struct MessageUnit __iomem *reg = acb->pmu; struct CMD_MESSAGE_FIELD *pcmdmessagefld; int retvalue = 0, transfer_len = 0; char *buffer; @@ -836,7 +1338,7 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, struct scsi_ (uint32_t ) cmd->cmnd[6] << 16 | (uint32_t ) cmd->cmnd[7] << 8 | (uint32_t ) cmd->cmnd[8]; - /* 4 bytes: Areca io control code */ + /* 4 bytes: Areca io control code */ sg = scsi_sglist(cmd); buffer = kmap_atomic(sg->page, KM_IRQ0) + sg->offset; @@ -852,194 +1354,199 @@ static int arcmsr_iop_message_xfer(struct AdapterControlBlock *acb, struct scsi_ } pcmdmessagefld = (struct CMD_MESSAGE_FIELD *) buffer; switch(controlcode) { + case ARCMSR_MESSAGE_READ_RQBUFFER: { - unsigned long *ver_addr; - dma_addr_t buf_handle; - uint8_t *pQbuffer, *ptmpQbuffer; - int32_t allxfer_len = 0; + unsigned long *ver_addr; + dma_addr_t buf_handle; + uint8_t *pQbuffer, *ptmpQbuffer; + int32_t allxfer_len = 0; + + ver_addr = pci_alloc_consistent(acb->pdev, 1032, &buf_handle); + if (!ver_addr) { + retvalue = ARCMSR_MESSAGE_FAIL; + goto message_out; + } + ptmpQbuffer = (uint8_t *) ver_addr; + while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex) + && (allxfer_len < 1031)) { + pQbuffer = &acb->rqbuffer[acb->rqbuf_firstindex]; + memcpy(ptmpQbuffer, pQbuffer, 1); + acb->rqbuf_firstindex++; + acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER; + ptmpQbuffer++; + allxfer_len++; + } + if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { - ver_addr = pci_alloc_consistent(acb->pdev, 1032, &buf_handle); - if (!ver_addr) { - retvalue = ARCMSR_MESSAGE_FAIL; - goto message_out; - } - ptmpQbuffer = (uint8_t *) ver_addr; - while ((acb->rqbuf_firstindex != acb->rqbuf_lastindex) - && (allxfer_len < 1031)) { - pQbuffer = &acb->rqbuffer[acb->rqbuf_firstindex]; - memcpy(ptmpQbuffer, pQbuffer, 1); - acb->rqbuf_firstindex++; - acb->rqbuf_firstindex %= ARCMSR_MAX_QBUFFER; - ptmpQbuffer++; - allxfer_len++; - } - if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { - struct QBUFFER __iomem * prbuffer = (struct QBUFFER __iomem *) - ®->message_rbuffer; - uint8_t __iomem * iop_data = (uint8_t __iomem *)prbuffer->data; - int32_t iop_len; - - acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; - iop_len = readl(&prbuffer->data_len); - while (iop_len > 0) { - acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data); - acb->rqbuf_lastindex++; - acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER; - iop_data++; - iop_len--; - } - writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, - ®->inbound_doorbell); + struct QBUFFER *prbuffer; + uint8_t *iop_data; + int32_t iop_len; + + acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; + prbuffer = arcmsr_get_iop_rqbuffer(acb); + iop_data = (uint8_t *)prbuffer->data; + iop_len = readl(&prbuffer->data_len); + while (iop_len > 0) { + acb->rqbuffer[acb->rqbuf_lastindex] = readb(iop_data); + acb->rqbuf_lastindex++; + acb->rqbuf_lastindex %= ARCMSR_MAX_QBUFFER; + iop_data++; + iop_len--; } - memcpy(pcmdmessagefld->messagedatabuffer, - (uint8_t *)ver_addr, allxfer_len); - pcmdmessagefld->cmdmessage.Length = allxfer_len; - pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; - pci_free_consistent(acb->pdev, 1032, ver_addr, buf_handle); + arcmsr_iop_message_read(acb); + } + memcpy(pcmdmessagefld->messagedatabuffer, (uint8_t *)ver_addr, allxfer_len); + pcmdmessagefld->cmdmessage.Length = allxfer_len; + pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; + pci_free_consistent(acb->pdev, 1032, ver_addr, buf_handle); } break; - case ARCMSR_MESSAGE_WRITE_WQBUFFER: { - unsigned long *ver_addr; - dma_addr_t buf_handle; - int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex; - uint8_t *pQbuffer, *ptmpuserbuffer; - ver_addr = pci_alloc_consistent(acb->pdev, 1032, &buf_handle); - if (!ver_addr) { - retvalue = ARCMSR_MESSAGE_FAIL; - goto message_out; - } - ptmpuserbuffer = (uint8_t *)ver_addr; - user_len = pcmdmessagefld->cmdmessage.Length; - memcpy(ptmpuserbuffer, pcmdmessagefld->messagedatabuffer, user_len); - wqbuf_lastindex = acb->wqbuf_lastindex; - wqbuf_firstindex = acb->wqbuf_firstindex; - if (wqbuf_lastindex != wqbuf_firstindex) { + case ARCMSR_MESSAGE_WRITE_WQBUFFER: { + unsigned long *ver_addr; + dma_addr_t buf_handle; + int32_t my_empty_len, user_len, wqbuf_firstindex, wqbuf_lastindex; + uint8_t *pQbuffer, *ptmpuserbuffer; + + ver_addr = pci_alloc_consistent(acb->pdev, 1032, &buf_handle); + if (!ver_addr) { + retvalue = ARCMSR_MESSAGE_FAIL; + goto message_out; + } + ptmpuserbuffer = (uint8_t *)ver_addr; + user_len = pcmdmessagefld->cmdmessage.Length; + memcpy(ptmpuserbuffer, pcmdmessagefld->messagedatabuffer, user_len); + wqbuf_lastindex = acb->wqbuf_lastindex; + wqbuf_firstindex = acb->wqbuf_firstindex; + if (wqbuf_lastindex != wqbuf_firstindex) { + struct SENSE_DATA *sensebuffer = + (struct SENSE_DATA *)cmd->sense_buffer; + arcmsr_post_ioctldata2iop(acb); + /* has error report sensedata */ + sensebuffer->ErrorCode = 0x70; + sensebuffer->SenseKey = ILLEGAL_REQUEST; + sensebuffer->AdditionalSenseLength = 0x0A; + sensebuffer->AdditionalSenseCode = 0x20; + sensebuffer->Valid = 1; + retvalue = ARCMSR_MESSAGE_FAIL; + } else { + my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1) + &(ARCMSR_MAX_QBUFFER - 1); + if (my_empty_len >= user_len) { + while (user_len > 0) { + pQbuffer = + &acb->wqbuffer[acb->wqbuf_lastindex]; + memcpy(pQbuffer, ptmpuserbuffer, 1); + acb->wqbuf_lastindex++; + acb->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER; + ptmpuserbuffer++; + user_len--; + } + if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) { + acb->acb_flags &= + ~ACB_F_MESSAGE_WQBUFFER_CLEARED; + arcmsr_post_ioctldata2iop(acb); + } + } else { + /* has error report sensedata */ struct SENSE_DATA *sensebuffer = (struct SENSE_DATA *)cmd->sense_buffer; - arcmsr_post_Qbuffer(acb); - /* has error report sensedata */ sensebuffer->ErrorCode = 0x70; sensebuffer->SenseKey = ILLEGAL_REQUEST; sensebuffer->AdditionalSenseLength = 0x0A; sensebuffer->AdditionalSenseCode = 0x20; sensebuffer->Valid = 1; retvalue = ARCMSR_MESSAGE_FAIL; - } else { - my_empty_len = (wqbuf_firstindex-wqbuf_lastindex - 1) - &(ARCMSR_MAX_QBUFFER - 1); - if (my_empty_len >= user_len) { - while (user_len > 0) { - pQbuffer = - &acb->wqbuffer[acb->wqbuf_lastindex]; - memcpy(pQbuffer, ptmpuserbuffer, 1); - acb->wqbuf_lastindex++; - acb->wqbuf_lastindex %= ARCMSR_MAX_QBUFFER; - ptmpuserbuffer++; - user_len--; - } - if (acb->acb_flags & ACB_F_MESSAGE_WQBUFFER_CLEARED) { - acb->acb_flags &= - ~ACB_F_MESSAGE_WQBUFFER_CLEARED; - arcmsr_post_Qbuffer(acb); - } - } else { - /* has error report sensedata */ - struct SENSE_DATA *sensebuffer = - (struct SENSE_DATA *)cmd->sense_buffer; - sensebuffer->ErrorCode = 0x70; - sensebuffer->SenseKey = ILLEGAL_REQUEST; - sensebuffer->AdditionalSenseLength = 0x0A; - sensebuffer->AdditionalSenseCode = 0x20; - sensebuffer->Valid = 1; - retvalue = ARCMSR_MESSAGE_FAIL; - } + } } pci_free_consistent(acb->pdev, 1032, ver_addr, buf_handle); } break; + case ARCMSR_MESSAGE_CLEAR_RQBUFFER: { - uint8_t *pQbuffer = acb->rqbuffer; + uint8_t *pQbuffer = acb->rqbuffer; - if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { - acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; - writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, - ®->inbound_doorbell); - } - acb->acb_flags |= ACB_F_MESSAGE_RQBUFFER_CLEARED; - acb->rqbuf_firstindex = 0; - acb->rqbuf_lastindex = 0; - memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER); - pcmdmessagefld->cmdmessage.ReturnCode = - ARCMSR_MESSAGE_RETURNCODE_OK; + if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { + acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; + arcmsr_iop_message_read(acb); + } + acb->acb_flags |= ACB_F_MESSAGE_RQBUFFER_CLEARED; + acb->rqbuf_firstindex = 0; + acb->rqbuf_lastindex = 0; + memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER); + pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; } break; + case ARCMSR_MESSAGE_CLEAR_WQBUFFER: { - uint8_t *pQbuffer = acb->wqbuffer; + uint8_t *pQbuffer = acb->wqbuffer; - if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { - acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; - writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK - , ®->inbound_doorbell); - } - acb->acb_flags |= - (ACB_F_MESSAGE_WQBUFFER_CLEARED | - ACB_F_MESSAGE_WQBUFFER_READED); - acb->wqbuf_firstindex = 0; - acb->wqbuf_lastindex = 0; - memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER); - pcmdmessagefld->cmdmessage.ReturnCode = - ARCMSR_MESSAGE_RETURNCODE_OK; + if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { + acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; + arcmsr_iop_message_read(acb); + } + acb->acb_flags |= + (ACB_F_MESSAGE_WQBUFFER_CLEARED | + ACB_F_MESSAGE_WQBUFFER_READED); + acb->wqbuf_firstindex = 0; + acb->wqbuf_lastindex = 0; + memset(pQbuffer, 0, ARCMSR_MAX_QBUFFER); + pcmdmessagefld->cmdmessage.ReturnCode = + ARCMSR_MESSAGE_RETURNCODE_OK; } break; + case ARCMSR_MESSAGE_CLEAR_ALLQBUFFER: { - uint8_t *pQbuffer; + uint8_t *pQbuffer; - if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { - acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; - writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK - , ®->inbound_doorbell); - } - acb->acb_flags |= - (ACB_F_MESSAGE_WQBUFFER_CLEARED - | ACB_F_MESSAGE_RQBUFFER_CLEARED - | ACB_F_MESSAGE_WQBUFFER_READED); - acb->rqbuf_firstindex = 0; - acb->rqbuf_lastindex = 0; - acb->wqbuf_firstindex = 0; - acb->wqbuf_lastindex = 0; - pQbuffer = acb->rqbuffer; - memset(pQbuffer, 0, sizeof (struct QBUFFER)); - pQbuffer = acb->wqbuffer; - memset(pQbuffer, 0, sizeof (struct QBUFFER)); - pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; + if (acb->acb_flags & ACB_F_IOPDATA_OVERFLOW) { + acb->acb_flags &= ~ACB_F_IOPDATA_OVERFLOW; + arcmsr_iop_message_read(acb); + } + acb->acb_flags |= + (ACB_F_MESSAGE_WQBUFFER_CLEARED + | ACB_F_MESSAGE_RQBUFFER_CLEARED + | ACB_F_MESSAGE_WQBUFFER_READED); + acb->rqbuf_firstindex = 0; + acb->rqbuf_lastindex = 0; + acb->wqbuf_firstindex = 0; + acb->wqbuf_lastindex = 0; + pQbuffer = acb->rqbuffer; + memset(pQbuffer, 0, sizeof(struct QBUFFER)); + pQbuffer = acb->wqbuffer; + memset(pQbuffer, 0, sizeof(struct QBUFFER)); + pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; } break; + case ARCMSR_MESSAGE_RETURN_CODE_3F: { - pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_3F; + pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_3F; } break; + case ARCMSR_MESSAGE_SAY_HELLO: { - int8_t * hello_string = "Hello! I am ARCMSR"; + int8_t *hello_string = "Hello! I am ARCMSR"; - memcpy(pcmdmessagefld->messagedatabuffer, hello_string - , (int16_t)strlen(hello_string)); - pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; + memcpy(pcmdmessagefld->messagedatabuffer, hello_string + , (int16_t)strlen(hello_string)); + pcmdmessagefld->cmdmessage.ReturnCode = ARCMSR_MESSAGE_RETURNCODE_OK; } break; + case ARCMSR_MESSAGE_SAY_GOODBYE: arcmsr_iop_parking(acb); break; + case ARCMSR_MESSAGE_FLUSH_ADAPTER_CACHE: arcmsr_flush_adapter_cache(acb); break; + default: retvalue = ARCMSR_MESSAGE_FAIL; } - message_out: + message_out: sg = scsi_sglist(cmd); kunmap_atomic(buffer - sg->offset, KM_IRQ0); - return retvalue; } @@ -1109,8 +1616,7 @@ static int arcmsr_queue_command(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *)) { struct Scsi_Host *host = cmd->device->host; - struct AdapterControlBlock *acb = - (struct AdapterControlBlock *) host->hostdata; + struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; struct CommandControlBlock *ccb; int target = cmd->device->id; int lun = cmd->device->lun; @@ -1153,26 +1659,27 @@ static int arcmsr_queue_command(struct scsi_cmnd *cmd, ccb = arcmsr_get_freeccb(acb); if (!ccb) return SCSI_MLQUEUE_HOST_BUSY; + arcmsr_build_ccb(acb, ccb, cmd); arcmsr_post_ccb(acb, ccb); return 0; } -static void arcmsr_get_firmware_spec(struct AdapterControlBlock *acb) +static void arcmsr_get_hba_config(struct AdapterControlBlock *acb) { - struct MessageUnit __iomem *reg = acb->pmu; + struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu; char *acb_firm_model = acb->firm_model; char *acb_firm_version = acb->firm_version; - char __iomem *iop_firm_model = (char __iomem *) ®->message_rwbuffer[15]; - char __iomem *iop_firm_version = (char __iomem *) ®->message_rwbuffer[17]; + char *iop_firm_model = (char *) (®->message_rwbuffer[15]); + char *iop_firm_version = (char *) (®->message_rwbuffer[17]); int count; writel(ARCMSR_INBOUND_MESG0_GET_CONFIG, ®->inbound_msgaddr0); - if (arcmsr_wait_msgint_ready(acb)) - printk(KERN_NOTICE - "arcmsr%d: wait " - "'get adapter firmware miscellaneous data' timeout \n" - , acb->host->host_no); + if (arcmsr_hba_wait_msgint_ready(acb)) { + printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \ + miscellaneous data' timeout \n", acb->host->host_no); + } + count = 8; while (count) { *acb_firm_model = readb(iop_firm_model); @@ -1180,6 +1687,7 @@ static void arcmsr_get_firmware_spec(struct AdapterControlBlock *acb) iop_firm_model++; count--; } + count = 16; while (count) { *acb_firm_version = readb(iop_firm_version); @@ -1187,28 +1695,93 @@ static void arcmsr_get_firmware_spec(struct AdapterControlBlock *acb) iop_firm_version++; count--; } - printk(KERN_INFO - "ARECA RAID ADAPTER%d: FIRMWARE VERSION %s \n" + + printk(KERN_INFO "ARECA RAID ADAPTER%d: FIRMWARE VERSION %s \n" , acb->host->host_no , acb->firm_version); + acb->firm_request_len = readl(®->message_rwbuffer[1]); acb->firm_numbers_queue = readl(®->message_rwbuffer[2]); acb->firm_sdram_size = readl(®->message_rwbuffer[3]); acb->firm_hd_channels = readl(®->message_rwbuffer[4]); } -static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb, +static void arcmsr_get_hbb_config(struct AdapterControlBlock *acb) +{ + struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu; + uint32_t *lrwbuffer = reg->msgcode_rwbuffer_reg; + char *acb_firm_model = acb->firm_model; + char *acb_firm_version = acb->firm_version; + char *iop_firm_model = (char *) (&lrwbuffer[15]); + /*firm_model,15,60-67*/ + char *iop_firm_version = (char *) (&lrwbuffer[17]); + /*firm_version,17,68-83*/ + int count; + + writel(ARCMSR_MESSAGE_GET_CONFIG, reg->drv2iop_doorbell_reg); + if (arcmsr_hbb_wait_msgint_ready(acb)) { + printk(KERN_NOTICE "arcmsr%d: wait 'get adapter firmware \ + miscellaneous data' timeout \n", acb->host->host_no); + } + + count = 8; + while (count) + { + *acb_firm_model = readb(iop_firm_model); + acb_firm_model++; + iop_firm_model++; + count--; + } + + count = 16; + while (count) + { + *acb_firm_version = readb(iop_firm_version); + acb_firm_version++; + iop_firm_version++; + count--; + } + + printk(KERN_INFO "ARECA RAID ADAPTER%d: FIRMWARE VERSION %s \n", + acb->host->host_no, + acb->firm_version); + + lrwbuffer++; + acb->firm_request_len = readl(lrwbuffer++); + /*firm_request_len,1,04-07*/ + acb->firm_numbers_queue = readl(lrwbuffer++); + /*firm_numbers_queue,2,08-11*/ + acb->firm_sdram_size = readl(lrwbuffer++); + /*firm_sdram_size,3,12-15*/ + acb->firm_hd_channels = readl(lrwbuffer); + /*firm_ide_channels,4,16-19*/ +} + +static void arcmsr_get_firmware_spec(struct AdapterControlBlock *acb) +{ + switch (acb->adapter_type) { + case ACB_ADAPTER_TYPE_A: { + arcmsr_get_hba_config(acb); + } + break; + + case ACB_ADAPTER_TYPE_B: { + arcmsr_get_hbb_config(acb); + } + break; + } +} + +static void arcmsr_polling_hba_ccbdone(struct AdapterControlBlock *acb, struct CommandControlBlock *poll_ccb) { - struct MessageUnit __iomem *reg = acb->pmu; + struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu; struct CommandControlBlock *ccb; uint32_t flag_ccb, outbound_intstatus, poll_ccb_done = 0, poll_count = 0; - int id, lun; - polling_ccb_retry: + polling_hba_ccb_retry: poll_count++; - outbound_intstatus = readl(®->outbound_intstatus) - & acb->outbound_int_enable; + outbound_intstatus = readl(®->outbound_intstatus) & acb->outbound_int_enable; writel(outbound_intstatus, ®->outbound_intstatus);/*clear interrupt*/ while (1) { if ((flag_ccb = readl(®->outbound_queueport)) == 0xFFFFFFFF) { @@ -1218,17 +1791,14 @@ static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb, msleep(25); if (poll_count > 100) break; - goto polling_ccb_retry; + goto polling_hba_ccb_retry; } } - ccb = (struct CommandControlBlock *) - (acb->vir2phy_offset + (flag_ccb << 5)); - if ((ccb->acb != acb) || - (ccb->startdone != ARCMSR_CCB_START)) { - if ((ccb->startdone == ARCMSR_CCB_ABORTED) || - (ccb == poll_ccb)) { - printk(KERN_NOTICE - "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'" + ccb = (struct CommandControlBlock *)(acb->vir2phy_offset + (flag_ccb << 5)); + poll_ccb_done = (ccb == poll_ccb) ? 1:0; + if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) { + if ((ccb->startdone == ARCMSR_CCB_ABORTED) || (ccb == poll_ccb)) { + printk(KERN_NOTICE "arcmsr%d: scsi id = %d lun = %d ccb = '0x%p'" " poll command abort successfully \n" , acb->host->host_no , ccb->pcmd->device->id @@ -1239,176 +1809,280 @@ static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb, poll_ccb_done = 1; continue; } - printk(KERN_NOTICE - "arcmsr%d: polling get an illegal ccb" - " command done ccb ='0x%p'" + printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb" + " command done ccb = '0x%p'" "ccboutstandingcount = %d \n" , acb->host->host_no , ccb , atomic_read(&acb->ccboutstandingcount)); continue; } - id = ccb->pcmd->device->id; - lun = ccb->pcmd->device->lun; - if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) { - if (acb->devstate[id][lun] == ARECA_RAID_GONE) - acb->devstate[id][lun] = ARECA_RAID_GOOD; - ccb->pcmd->result = DID_OK << 16; - arcmsr_ccb_complete(ccb, 1); - } else { - switch(ccb->arcmsr_cdb.DeviceStatus) { - case ARCMSR_DEV_SELECT_TIMEOUT: { - acb->devstate[id][lun] = ARECA_RAID_GONE; - ccb->pcmd->result = DID_NO_CONNECT << 16; - arcmsr_ccb_complete(ccb, 1); - } - break; - case ARCMSR_DEV_ABORTED: - case ARCMSR_DEV_INIT_FAIL: { - acb->devstate[id][lun] = ARECA_RAID_GONE; - ccb->pcmd->result = DID_BAD_TARGET << 16; - arcmsr_ccb_complete(ccb, 1); + arcmsr_report_ccb_state(acb, ccb, flag_ccb); + } +} + +static void arcmsr_polling_hbb_ccbdone(struct AdapterControlBlock *acb, \ + struct CommandControlBlock *poll_ccb) +{ + struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu; + struct CommandControlBlock *ccb; + uint32_t flag_ccb, poll_ccb_done = 0, poll_count = 0; + int index; + + polling_hbb_ccb_retry: + poll_count++; + /* clear doorbell interrupt */ + writel(ARCMSR_DOORBELL_INT_CLEAR_PATTERN, reg->iop2drv_doorbell_reg); + while (1) { + index = reg->doneq_index; + if ((flag_ccb = readl(®->done_qbuffer[index])) == 0) { + if (poll_ccb_done) + break; + else { + msleep(25); + if (poll_count > 100) + break; + goto polling_hbb_ccb_retry; } - break; - case ARCMSR_DEV_CHECK_CONDITION: { - acb->devstate[id][lun] = ARECA_RAID_GOOD; - arcmsr_report_sense_info(ccb); + } + writel(0, ®->done_qbuffer[index]); + index++; + /*if last index number set it to 0 */ + index %= ARCMSR_MAX_HBB_POSTQUEUE; + reg->doneq_index = index; + /* check ifcommand done with no error*/ + ccb = (struct CommandControlBlock *)\ + (acb->vir2phy_offset + (flag_ccb << 5));/*frame must be 32 bytes aligned*/ + poll_ccb_done = (ccb == poll_ccb) ? 1:0; + if ((ccb->acb != acb) || (ccb->startdone != ARCMSR_CCB_START)) { + if (ccb->startdone == ARCMSR_CCB_ABORTED) { + printk(KERN_NOTICE "arcmsr%d: \ + scsi id = %d lun = %d ccb = '0x%p' poll command abort successfully \n" + ,acb->host->host_no + ,ccb->pcmd->device->id + ,ccb->pcmd->device->lun + ,ccb); + ccb->pcmd->result = DID_ABORT << 16; arcmsr_ccb_complete(ccb, 1); + continue; } - break; - default: - printk(KERN_NOTICE - "arcmsr%d: scsi id = %d lun = %d" - " polling and getting command error done" - "but got unknown DeviceStatus = 0x%x \n" + printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb" + " command done ccb = '0x%p'" + "ccboutstandingcount = %d \n" , acb->host->host_no - , id - , lun - , ccb->arcmsr_cdb.DeviceStatus); - acb->devstate[id][lun] = ARECA_RAID_GONE; - ccb->pcmd->result = DID_BAD_TARGET << 16; - arcmsr_ccb_complete(ccb, 1); - break; + , ccb + , atomic_read(&acb->ccboutstandingcount)); + continue; } + arcmsr_report_ccb_state(acb, ccb, flag_ccb); + } /*drain reply FIFO*/ +} + +static void arcmsr_polling_ccbdone(struct AdapterControlBlock *acb, \ + struct CommandControlBlock *poll_ccb) +{ + switch (acb->adapter_type) { + + case ACB_ADAPTER_TYPE_A: { + arcmsr_polling_hba_ccbdone(acb,poll_ccb); + } + break; + + case ACB_ADAPTER_TYPE_B: { + arcmsr_polling_hbb_ccbdone(acb,poll_ccb); } } } -static void arcmsr_done4_abort_postqueue(struct AdapterControlBlock *acb) + +static int arcmsr_iop_confirm(struct AdapterControlBlock *acb) { - int i = 0, found = 0; - int id, lun; - uint32_t flag_ccb, outbound_intstatus; - struct MessageUnit __iomem *reg = acb->pmu; - struct CommandControlBlock *ccb; - /*clear and abort all outbound posted Q*/ - - while (((flag_ccb = readl(®->outbound_queueport)) != 0xFFFFFFFF) && -(i++ < 256)){ - ccb = (struct CommandControlBlock *)(acb->vir2phy_offset + -(flag_ccb << 5)); - if (ccb){ - if ((ccb->acb != acb)||(ccb->startdone != \ -ARCMSR_CCB_START)){ - printk(KERN_NOTICE "arcmsr%d: polling get \ -an illegal ccb" "command done ccb = '0x%p'""ccboutstandingcount = %d \n", - acb->host->host_no, ccb, - atomic_read(&acb->ccboutstandingcount)); - continue; + uint32_t cdb_phyaddr, ccb_phyaddr_hi32; + dma_addr_t dma_coherent_handle; + /* + ******************************************************************** + ** here we need to tell iop 331 our freeccb.HighPart + ** if freeccb.HighPart is not zero + ******************************************************************** + */ + dma_coherent_handle = acb->dma_coherent_handle; + cdb_phyaddr = (uint32_t)(dma_coherent_handle); + ccb_phyaddr_hi32 = (uint32_t)((cdb_phyaddr >> 16) >> 16); + /* + *********************************************************************** + ** if adapter type B, set window of "post command Q" + *********************************************************************** + */ + switch (acb->adapter_type) { + + case ACB_ADAPTER_TYPE_A: { + if (ccb_phyaddr_hi32 != 0) { + struct MessageUnit_A __iomem *reg = \ + (struct MessageUnit_A *)acb->pmu; + uint32_t intmask_org; + intmask_org = arcmsr_disable_outbound_ints(acb); + writel(ARCMSR_SIGNATURE_SET_CONFIG, \ + ®->message_rwbuffer[0]); + writel(ccb_phyaddr_hi32, ®->message_rwbuffer[1]); + writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, \ + ®->inbound_msgaddr0); + if (arcmsr_hba_wait_msgint_ready(acb)) { + printk(KERN_NOTICE "arcmsr%d: ""set ccb high \ + part physical address timeout\n", + acb->host->host_no); + return 1; } + arcmsr_enable_outbound_ints(acb, intmask_org); + } + } + break; - id = ccb->pcmd->device->id; - lun = ccb->pcmd->device->lun; - if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)){ - if (acb->devstate[id][lun] == ARECA_RAID_GONE) - acb->devstate[id][lun] = ARECA_RAID_GOOD; - ccb->pcmd->result = DID_OK << 16; - arcmsr_ccb_complete(ccb, 1); - } - else { - switch(ccb->arcmsr_cdb.DeviceStatus) { - case ARCMSR_DEV_SELECT_TIMEOUT: { - acb->devstate[id][lun] = ARECA_RAID_GONE; - ccb->pcmd->result = DID_NO_CONNECT << 16; - arcmsr_ccb_complete(ccb, 1); - } - break; + case ACB_ADAPTER_TYPE_B: { + unsigned long post_queue_phyaddr; + uint32_t *rwbuffer; - case ARCMSR_DEV_ABORTED: + struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu; + uint32_t intmask_org; + intmask_org = arcmsr_disable_outbound_ints(acb); + reg->postq_index = 0; + reg->doneq_index = 0; + writel(ARCMSR_MESSAGE_SET_POST_WINDOW, reg->drv2iop_doorbell_reg); + if (arcmsr_hbb_wait_msgint_ready(acb)) { + printk(KERN_NOTICE "arcmsr%d:can not set diver mode\n", \ + acb->host->host_no); + return 1; + } + post_queue_phyaddr = cdb_phyaddr + ARCMSR_MAX_FREECCB_NUM * \ + sizeof(struct CommandControlBlock) + offsetof(struct MessageUnit_B, post_qbuffer) ; + rwbuffer = reg->msgcode_rwbuffer_reg; + /* driver "set config" signature */ + writel(ARCMSR_SIGNATURE_SET_CONFIG, rwbuffer++); + /* normal should be zero */ + writel(ccb_phyaddr_hi32, rwbuffer++); + /* postQ size (256 + 8)*4 */ + writel(post_queue_phyaddr, rwbuffer++); + /* doneQ size (256 + 8)*4 */ + writel(post_queue_phyaddr + 1056, rwbuffer++); + /* ccb maxQ size must be --> [(256 + 8)*4]*/ + writel(1056, rwbuffer); + + writel(ARCMSR_MESSAGE_SET_CONFIG, reg->drv2iop_doorbell_reg); + if (arcmsr_hbb_wait_msgint_ready(acb)) { + printk(KERN_NOTICE "arcmsr%d: 'set command Q window' \ + timeout \n",acb->host->host_no); + return 1; + } - case ARCMSR_DEV_INIT_FAIL: { - acb->devstate[id][lun] = - ARECA_RAID_GONE; - ccb->pcmd->result = - DID_BAD_TARGET << 16; - arcmsr_ccb_complete(ccb, 1); - } - break; + writel(ARCMSR_MESSAGE_START_DRIVER_MODE, reg->drv2iop_doorbell_reg); + if (arcmsr_hbb_wait_msgint_ready(acb)) { + printk(KERN_NOTICE "arcmsr%d: 'can not set diver mode \n"\ + ,acb->host->host_no); + return 1; + } + arcmsr_enable_outbound_ints(acb, intmask_org); + } + break; + } + return 0; +} - case ARCMSR_DEV_CHECK_CONDITION: { - acb->devstate[id][lun] = - ARECA_RAID_GOOD; - arcmsr_report_sense_info(ccb); - arcmsr_ccb_complete(ccb, 1); - } - break; +static void arcmsr_wait_firmware_ready(struct AdapterControlBlock *acb) +{ + uint32_t firmware_state = 0; - default: - printk(KERN_NOTICE - "arcmsr%d: scsi id = %d \ - lun = %d""polling and \ - getting command error \ - done""but got unknown \ - DeviceStatus = 0x%x \n", - acb->host->host_no, id, - lun, ccb->arcmsr_cdb.DeviceStatus); - acb->devstate[id][lun] = - ARECA_RAID_GONE; - ccb->pcmd->result = - DID_BAD_TARGET << 16; - arcmsr_ccb_complete(ccb, 1); - break; - } - } - found = 1; - } + switch (acb->adapter_type) { + + case ACB_ADAPTER_TYPE_A: { + struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu; + do { + firmware_state = readl(®->outbound_msgaddr1); + } while ((firmware_state & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK) == 0); + } + break; + + case ACB_ADAPTER_TYPE_B: { + struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu; + do { + firmware_state = readl(reg->iop2drv_doorbell_reg); + } while ((firmware_state & ARCMSR_MESSAGE_FIRMWARE_OK) == 0); + } + break; } - if (found){ - outbound_intstatus = readl(®->outbound_intstatus) & \ - acb->outbound_int_enable; - writel(outbound_intstatus, ®->outbound_intstatus); - /*clear interrupt*/ +} + +static void arcmsr_start_hba_bgrb(struct AdapterControlBlock *acb) +{ + struct MessageUnit_A __iomem *reg = (struct MessageUnit_A *)acb->pmu; + acb->acb_flags |= ACB_F_MSG_START_BGRB; + writel(ARCMSR_INBOUND_MESG0_START_BGRB, ®->inbound_msgaddr0); + if (arcmsr_hba_wait_msgint_ready(acb)) { + printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \ + rebulid' timeout \n", acb->host->host_no); } - return; } +static void arcmsr_start_hbb_bgrb(struct AdapterControlBlock *acb) +{ + struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu; + acb->acb_flags |= ACB_F_MSG_START_BGRB; + writel(ARCMSR_MESSAGE_START_BGRB, reg->drv2iop_doorbell_reg); + if (arcmsr_hbb_wait_msgint_ready(acb)) { + printk(KERN_NOTICE "arcmsr%d: wait 'start adapter background \ + rebulid' timeout \n",acb->host->host_no); + } +} -static void arcmsr_iop_init(struct AdapterControlBlock *acb) +static void arcmsr_start_adapter_bgrb(struct AdapterControlBlock *acb) { - struct MessageUnit __iomem *reg = acb->pmu; - uint32_t intmask_org, mask, outbound_doorbell, firmware_state = 0; + switch (acb->adapter_type) { + case ACB_ADAPTER_TYPE_A: + arcmsr_start_hba_bgrb(acb); + break; + case ACB_ADAPTER_TYPE_B: + arcmsr_start_hbb_bgrb(acb); + break; + } +} - do { - firmware_state = readl(®->outbound_msgaddr1); - } while (!(firmware_state & ARCMSR_OUTBOUND_MESG1_FIRMWARE_OK)); - intmask_org = readl(®->outbound_intmask) - | ARCMSR_MU_OUTBOUND_MESSAGE0_INTMASKENABLE; - arcmsr_get_firmware_spec(acb); +static void arcmsr_clear_doorbell_queue_buffer(struct AdapterControlBlock *acb) +{ + switch (acb->adapter_type) { + case ACB_ADAPTER_TYPE_A: { + struct MessageUnit_A *reg = (struct MessageUnit_A *)acb->pmu; + uint32_t outbound_doorbell; + /* empty doorbell Qbuffer if door bell ringed */ + outbound_doorbell = readl(®->outbound_doorbell); + /*clear doorbell interrupt */ + writel(outbound_doorbell, ®->outbound_doorbell); + writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, ®->inbound_doorbell); + } + break; - acb->acb_flags |= ACB_F_MSG_START_BGRB; - writel(ARCMSR_INBOUND_MESG0_START_BGRB, ®->inbound_msgaddr0); - if (arcmsr_wait_msgint_ready(acb)) { - printk(KERN_NOTICE "arcmsr%d: " - "wait 'start adapter background rebulid' timeout\n", - acb->host->host_no); + case ACB_ADAPTER_TYPE_B: { + struct MessageUnit_B *reg = (struct MessageUnit_B *)acb->pmu; + /*clear interrupt and message state*/ + writel(ARCMSR_MESSAGE_INT_CLEAR_PATTERN, reg->iop2drv_doorbell_reg); + writel(ARCMSR_DRV2IOP_DATA_READ_OK, reg->drv2iop_doorbell_reg); + /* let IOP know data has been read */ + } + break; } +} - outbound_doorbell = readl(®->outbound_doorbell); - writel(outbound_doorbell, ®->outbound_doorbell); - writel(ARCMSR_INBOUND_DRIVER_DATA_READ_OK, ®->inbound_doorbell); - mask = ~(ARCMSR_MU_OUTBOUND_POSTQUEUE_INTMASKENABLE - | ARCMSR_MU_OUTBOUND_DOORBELL_INTMASKENABLE); - writel(intmask_org & mask, ®->outbound_intmask); - acb->outbound_int_enable = ~(intmask_org & mask) & 0x000000ff; +static void arcmsr_iop_init(struct AdapterControlBlock *acb) +{ + uint32_t intmask_org; + + arcmsr_wait_firmware_ready(acb); + arcmsr_iop_confirm(acb); + /* disable all outbound interrupt */ + intmask_org = arcmsr_disable_outbound_ints(acb); + arcmsr_get_firmware_spec(acb); + /*start background rebuild*/ + arcmsr_start_adapter_bgrb(acb); + /* empty doorbell Qbuffer if door bell ringed */ + arcmsr_clear_doorbell_queue_buffer(acb); + /* enable outbound Post Queue,outbound doorbell Interrupt */ + arcmsr_enable_outbound_ints(acb, intmask_org); acb->acb_flags |= ACB_F_IOP_INITED; } @@ -1422,21 +2096,21 @@ static void arcmsr_iop_reset(struct AdapterControlBlock *acb) /* talk to iop 331 outstanding command aborted */ arcmsr_abort_allcmd(acb); /* wait for 3 sec for all command aborted*/ - msleep_interruptible(3000); + ssleep(3); /* disable all outbound interrupt */ intmask_org = arcmsr_disable_outbound_ints(acb); /* clear all outbound posted Q */ - arcmsr_done4_abort_postqueue(acb); + arcmsr_done4abort_postqueue(acb); for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { ccb = acb->pccb_pool[i]; if (ccb->startdone == ARCMSR_CCB_START) { ccb->startdone = ARCMSR_CCB_ABORTED; + arcmsr_ccb_complete(ccb, 1); } } /* enable all outbound interrupt */ arcmsr_enable_outbound_ints(acb, intmask_org); } - } static int arcmsr_bus_reset(struct scsi_cmnd *cmd) @@ -1450,7 +2124,7 @@ static int arcmsr_bus_reset(struct scsi_cmnd *cmd) for (i = 0; i < 400; i++) { if (!atomic_read(&acb->ccboutstandingcount)) break; - arcmsr_interrupt(acb); + arcmsr_interrupt(acb);/* FIXME: need spinlock */ msleep(25); } arcmsr_iop_reset(acb); @@ -1468,7 +2142,7 @@ static void arcmsr_abort_one_cmd(struct AdapterControlBlock *acb, /* ** Wait for 3 sec for all command done. */ - msleep_interruptible(3000); + ssleep(3); intmask = arcmsr_disable_outbound_ints(acb); arcmsr_polling_ccbdone(acb, ccb); @@ -1515,6 +2189,8 @@ static const char *arcmsr_info(struct Scsi_Host *host) switch (acb->pdev->device) { case PCI_DEVICE_ID_ARECA_1110: + case PCI_DEVICE_ID_ARECA_1200: + case PCI_DEVICE_ID_ARECA_1202: case PCI_DEVICE_ID_ARECA_1210: raid6 = 0; /*FALLTHRU*/ @@ -1522,6 +2198,7 @@ static const char *arcmsr_info(struct Scsi_Host *host) case PCI_DEVICE_ID_ARECA_1130: case PCI_DEVICE_ID_ARECA_1160: case PCI_DEVICE_ID_ARECA_1170: + case PCI_DEVICE_ID_ARECA_1201: case PCI_DEVICE_ID_ARECA_1220: case PCI_DEVICE_ID_ARECA_1230: case PCI_DEVICE_ID_ARECA_1260: @@ -1544,287 +2221,82 @@ static const char *arcmsr_info(struct Scsi_Host *host) ARCMSR_DRIVER_VERSION); return buf; } - +#ifdef CONFIG_SCSI_ARCMSR_AER static pci_ers_result_t arcmsr_pci_slot_reset(struct pci_dev *pdev) { - struct Scsi_Host *host; - struct AdapterControlBlock *acb; - uint8_t bus, dev_fun; - int error; - - error = pci_enable_device(pdev); - if (error) - return PCI_ERS_RESULT_DISCONNECT; - pci_set_master(pdev); - - host = scsi_host_alloc(&arcmsr_scsi_host_template, sizeof \ -(struct AdapterControlBlock)); - if (!host) - return PCI_ERS_RESULT_DISCONNECT; - acb = (struct AdapterControlBlock *)host->hostdata; - memset(acb, 0, sizeof (struct AdapterControlBlock)); - - error = pci_set_dma_mask(pdev, DMA_64BIT_MASK); - if (error) { - error = pci_set_dma_mask(pdev, DMA_32BIT_MASK); - if (error) { - printk(KERN_WARNING - "scsi%d: No suitable DMA mask available\n", - host->host_no); - return PCI_ERS_RESULT_DISCONNECT; - } - } - bus = pdev->bus->number; - dev_fun = pdev->devfn; - acb = (struct AdapterControlBlock *) host->hostdata; - memset(acb, 0, sizeof(struct AdapterControlBlock)); - acb->pdev = pdev; - acb->host = host; - host->max_sectors = ARCMSR_MAX_XFER_SECTORS; - host->max_lun = ARCMSR_MAX_TARGETLUN; - host->max_id = ARCMSR_MAX_TARGETID;/*16:8*/ - host->max_cmd_len = 16; /*this is issue of 64bit LBA, over 2T byte*/ - host->sg_tablesize = ARCMSR_MAX_SG_ENTRIES; - host->can_queue = ARCMSR_MAX_FREECCB_NUM; /* max simultaneous cmds */ - host->cmd_per_lun = ARCMSR_MAX_CMD_PERLUN; - host->this_id = ARCMSR_SCSI_INITIATOR_ID; - host->unique_id = (bus << 8) | dev_fun; - host->irq = pdev->irq; - error = pci_request_regions(pdev, "arcmsr"); - if (error) - return PCI_ERS_RESULT_DISCONNECT; + struct Scsi_Host *host = pci_get_drvdata(pdev); + struct AdapterControlBlock *acb = + (struct AdapterControlBlock *) host->hostdata; + uint32_t intmask_org; + int i, j; - acb->pmu = ioremap(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0)); - if (!acb->pmu) { - printk(KERN_NOTICE "arcmsr%d: memory" - " mapping region fail \n", acb->host->host_no); + if (pci_enable_device(pdev)) { return PCI_ERS_RESULT_DISCONNECT; } + pci_set_master(pdev); + intmask_org = arcmsr_disable_outbound_ints(acb); acb->acb_flags |= (ACB_F_MESSAGE_WQBUFFER_CLEARED | ACB_F_MESSAGE_RQBUFFER_CLEARED | ACB_F_MESSAGE_WQBUFFER_READED); acb->acb_flags &= ~ACB_F_SCSISTOPADAPTER; - INIT_LIST_HEAD(&acb->ccb_free_list); - - error = arcmsr_alloc_ccb_pool(acb); - if (error) - return PCI_ERS_RESULT_DISCONNECT; - - error = request_irq(pdev->irq, arcmsr_do_interrupt, - IRQF_DISABLED | IRQF_SHARED, "arcmsr", acb); - if (error) - return PCI_ERS_RESULT_DISCONNECT; - - arcmsr_iop_init(acb); - if (strncmp(acb->firm_version, "V1.42", 5) >= 0) - host->max_sectors = ARCMSR_MAX_XFER_SECTORS_B; - - pci_set_drvdata(pdev, host); - - error = scsi_add_host(host, &pdev->dev); - if (error) - return PCI_ERS_RESULT_DISCONNECT; + for (i = 0; i < ARCMSR_MAX_TARGETID; i++) + for (j = 0; j < ARCMSR_MAX_TARGETLUN; j++) + acb->devstate[i][j] = ARECA_RAID_GONE; - error = arcmsr_alloc_sysfs_attr(acb); - if (error) - return PCI_ERS_RESULT_DISCONNECT; + arcmsr_wait_firmware_ready(acb); + arcmsr_iop_confirm(acb); + /* disable all outbound interrupt */ + arcmsr_get_firmware_spec(acb); + /*start background rebuild*/ + arcmsr_start_adapter_bgrb(acb); + /* empty doorbell Qbuffer if door bell ringed */ + arcmsr_clear_doorbell_queue_buffer(acb); + /* enable outbound Post Queue,outbound doorbell Interrupt */ + arcmsr_enable_outbound_ints(acb, intmask_org); + acb->acb_flags |= ACB_F_IOP_INITED; - scsi_scan_host(host); + pci_enable_pcie_error_reporting(pdev); return PCI_ERS_RESULT_RECOVERED; } static void arcmsr_pci_ers_need_reset_forepart(struct pci_dev *pdev) { struct Scsi_Host *host = pci_get_drvdata(pdev); - struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; - struct MessageUnit __iomem *reg = acb->pmu; + struct AdapterControlBlock *acb = (struct AdapterControlBlock *)host->hostdata; struct CommandControlBlock *ccb; - /*clear and abort all outbound posted Q*/ - int i = 0, found = 0; - int id, lun; - uint32_t flag_ccb, outbound_intstatus; - - while (((flag_ccb = readl(®->outbound_queueport)) != 0xFFFFFFFF) && - (i++ < 256)){ - ccb = (struct CommandControlBlock *)(acb->vir2phy_offset - + (flag_ccb << 5)); - if (ccb){ - if ((ccb->acb != acb)||(ccb->startdone != - ARCMSR_CCB_START)){ - printk(KERN_NOTICE "arcmsr%d: polling \ - get an illegal ccb"" command done ccb = '0x%p'" - "ccboutstandingcount = %d \n", - acb->host->host_no, ccb, - atomic_read(&acb->ccboutstandingcount)); - continue; - } - - id = ccb->pcmd->device->id; - lun = ccb->pcmd->device->lun; - if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) { - if (acb->devstate[id][lun] == - ARECA_RAID_GONE) - acb->devstate[id][lun] = - ARECA_RAID_GOOD; - ccb->pcmd->result = DID_OK << 16; - arcmsr_ccb_complete(ccb, 1); - } - else { - switch(ccb->arcmsr_cdb.DeviceStatus) { - case ARCMSR_DEV_SELECT_TIMEOUT: { - acb->devstate[id][lun] = - ARECA_RAID_GONE; - ccb->pcmd->result = - DID_NO_CONNECT << 16; - arcmsr_ccb_complete(ccb, 1); - } - break; - - case ARCMSR_DEV_ABORTED: - - case ARCMSR_DEV_INIT_FAIL: { - acb->devstate[id][lun] = - ARECA_RAID_GONE; - ccb->pcmd->result = - DID_BAD_TARGET << 16; - arcmsr_ccb_complete(ccb, 1); - } - break; - - case ARCMSR_DEV_CHECK_CONDITION: { - acb->devstate[id][lun] = - ARECA_RAID_GOOD; - arcmsr_report_sense_info(ccb); - arcmsr_ccb_complete(ccb, 1); - } - break; + uint32_t intmask_org; + int i = 0; - default: - printk(KERN_NOTICE - "arcmsr%d: scsi \ - id = %d lun = %d" - " polling and \ - getting command \ - error done" - "but got unknown \ - DeviceStatus = 0x%x \n" - , acb->host->host_no, - id, lun, - ccb->arcmsr_cdb.DeviceStatus); - acb->devstate[id][lun] = - ARECA_RAID_GONE; - ccb->pcmd->result = - DID_BAD_TARGET << 16; - arcmsr_ccb_complete(ccb, 1); - break; - } - } - found = 1; + if (atomic_read(&acb->ccboutstandingcount) != 0) { + /* talk to iop 331 outstanding command aborted */ + arcmsr_abort_allcmd(acb); + /* wait for 3 sec for all command aborted*/ + ssleep(3); + /* disable all outbound interrupt */ + intmask_org = arcmsr_disable_outbound_ints(acb); + /* clear all outbound posted Q */ + arcmsr_done4abort_postqueue(acb); + for (i = 0; i < ARCMSR_MAX_FREECCB_NUM; i++) { + ccb = acb->pccb_pool[i]; + if (ccb->startdone == ARCMSR_CCB_START) { + ccb->startdone = ARCMSR_CCB_ABORTED; + arcmsr_ccb_complete(ccb, 1); } } - if (found){ - outbound_intstatus = readl(®->outbound_intstatus) & - acb->outbound_int_enable; - writel(outbound_intstatus, ®->outbound_intstatus); - /*clear interrupt*/ - } - return; + /* enable all outbound interrupt */ + arcmsr_enable_outbound_ints(acb, intmask_org); + } + pci_disable_device(pdev); } - static void arcmsr_pci_ers_disconnect_forepart(struct pci_dev *pdev) { - struct Scsi_Host *host = pci_get_drvdata(pdev); - struct AdapterControlBlock *acb = (struct AdapterControlBlock *) host->hostdata; - struct MessageUnit __iomem *reg = acb->pmu; - struct CommandControlBlock *ccb; - /*clear and abort all outbound posted Q*/ - int i = 0, found = 0; - int id, lun; - uint32_t flag_ccb, outbound_intstatus; - - while (((flag_ccb = readl(®->outbound_queueport)) != 0xFFFFFFFF) && - (i++ < 256)){ - ccb = (struct CommandControlBlock *)(acb->vir2phy_offset + - (flag_ccb << 5)); - if (ccb){ - if ((ccb->acb != acb)||(ccb->startdone != - ARCMSR_CCB_START)){ - printk(KERN_NOTICE - "arcmsr%d: polling get an illegal ccb" - " command done ccb = '0x%p'" - "ccboutstandingcount = %d \n", - acb->host->host_no, ccb, - atomic_read(&acb->ccboutstandingcount)); - continue; - } - - id = ccb->pcmd->device->id; - lun = ccb->pcmd->device->lun; - if (!(flag_ccb & ARCMSR_CCBREPLY_FLAG_ERROR)) { - if (acb->devstate[id][lun] == ARECA_RAID_GONE) - acb->devstate[id][lun] = ARECA_RAID_GOOD; - ccb->pcmd->result = DID_OK << 16; - arcmsr_ccb_complete(ccb, 1); - } - else { - switch(ccb->arcmsr_cdb.DeviceStatus) { - case ARCMSR_DEV_SELECT_TIMEOUT: { - acb->devstate[id][lun] = - ARECA_RAID_GONE; - ccb->pcmd->result = - DID_NO_CONNECT << 16; - arcmsr_ccb_complete(ccb, 1); - } - break; - - case ARCMSR_DEV_ABORTED: - - case ARCMSR_DEV_INIT_FAIL: { - acb->devstate[id][lun] = - ARECA_RAID_GONE; - ccb->pcmd->result = - DID_BAD_TARGET << 16; - arcmsr_ccb_complete(ccb, 1); - } - break; - - case ARCMSR_DEV_CHECK_CONDITION: { - acb->devstate[id][lun] = - ARECA_RAID_GOOD; - arcmsr_report_sense_info(ccb); - arcmsr_ccb_complete(ccb, 1); - } - break; + struct Scsi_Host *host = pci_get_drvdata(pdev); + struct AdapterControlBlock *acb = \ + (struct AdapterControlBlock *)host->hostdata; - default: - printk(KERN_NOTICE "arcmsr%d: \ - scsi id = %d lun = %d" - " polling and \ - getting command error done" - "but got unknown \ - DeviceStatus = 0x%x \n" - , acb->host->host_no, - id, lun, ccb->arcmsr_cdb.DeviceStatus); - acb->devstate[id][lun] = - ARECA_RAID_GONE; - ccb->pcmd->result = - DID_BAD_TARGET << 16; - arcmsr_ccb_complete(ccb, 1); - break; - } - } - found = 1; - } - } - if (found){ - outbound_intstatus = readl(®->outbound_intstatus) & - acb->outbound_int_enable; - writel(outbound_intstatus, ®->outbound_intstatus); - /*clear interrupt*/ - } - return; + arcmsr_stop_adapter_bgrb(acb); + arcmsr_flush_adapter_cache(acb); } static pci_ers_result_t arcmsr_pci_error_detected(struct pci_dev *pdev, @@ -1840,5 +2312,6 @@ static pci_ers_result_t arcmsr_pci_error_detected(struct pci_dev *pdev, break; default: return PCI_ERS_RESULT_NEED_RESET; - } + } } +#endif diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 715a23e4a1e9..92dc6ca840d4 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2057,6 +2057,9 @@ #define PCI_DEVICE_ID_ARECA_1130 0x1130 #define PCI_DEVICE_ID_ARECA_1160 0x1160 #define PCI_DEVICE_ID_ARECA_1170 0x1170 +#define PCI_DEVICE_ID_ARECA_1200 0x1200 +#define PCI_DEVICE_ID_ARECA_1201 0x1201 +#define PCI_DEVICE_ID_ARECA_1202 0x1202 #define PCI_DEVICE_ID_ARECA_1210 0x1210 #define PCI_DEVICE_ID_ARECA_1220 0x1220 #define PCI_DEVICE_ID_ARECA_1230 0x1230 -- cgit v1.2.3 From 9d511a4b29de6764931343d03e493f2e04df0271 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 2 Oct 2007 21:55:42 -0400 Subject: [SCSI] advansys: Changes to work on parisc Change PortAddr to be an unsigned int instead of an unsigned short (IO Port address are 24 bit on parisc). Fix a couple of printk argument warnings. Remove the Kconfig marking as 'BROKEN'. I haven't removed the #warning yet because virt_to_bus/bus_to_virt are only eliminated for narrow boards. Wide boards need more work. Signed-off-by: Matthew Wilcox Signed-off-by: James Bottomley --- drivers/scsi/Kconfig | 1 - drivers/scsi/advansys.c | 10 +++++----- 2 files changed, 5 insertions(+), 6 deletions(-) (limited to 'drivers/scsi/Kconfig') diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 69b2fac6f098..de6a6418df24 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -521,7 +521,6 @@ config SCSI_ADVANSYS tristate "AdvanSys SCSI support" depends on SCSI depends on ISA || EISA || PCI - depends on BROKEN || X86_32 help This is a driver for all SCSI host adapters manufactured by AdvanSys. It is documented in the kernel source in diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c index 07507a7e9c50..9dd3952516c5 100644 --- a/drivers/scsi/advansys.c +++ b/drivers/scsi/advansys.c @@ -120,7 +120,7 @@ typedef unsigned char uchar; #define CC_VERY_LONG_SG_LIST 0 #define ASC_SRB2SCSIQ(srb_ptr) (srb_ptr) -#define PortAddr unsigned short /* port address size */ +#define PortAddr unsigned int /* port address size */ #define inp(port) inb(port) #define outp(port, byte) outb((byte), (port)) @@ -13333,8 +13333,8 @@ static int __devinit advansys_wide_init_chip(struct Scsi_Host *shost) } - ASC_DBG(1, "sg_cnt %d * %u = %u bytes\n", sg_cnt, sizeof(adv_sgblk_t), - (unsigned)(sizeof(adv_sgblk_t) * sg_cnt)); + ASC_DBG(1, "sg_cnt %d * %lu = %lu bytes\n", sg_cnt, sizeof(adv_sgblk_t), + sizeof(adv_sgblk_t) * sg_cnt); if (!board->adv_sgblkp) goto kmalloc_failed; @@ -13428,9 +13428,9 @@ static int __devinit advansys_board_found(struct Scsi_Host *shost, boardp->ioremap_addr = ioremap(pci_resource_start(pdev, 1), boardp->asc_n_io_port); if (!boardp->ioremap_addr) { - shost_printk(KERN_ERR, shost, "ioremap(%x, %d) " + shost_printk(KERN_ERR, shost, "ioremap(%lx, %d) " "returned NULL\n", - pci_resource_start(pdev, 1), + (long)pci_resource_start(pdev, 1), boardp->asc_n_io_port); ret = -ENODEV; goto err_shost; -- cgit v1.2.3