Message ID | 20151028220656.5323.34704.stgit@brunhilda (mailing list archive) |
---|---|
State | Superseded, archived |
Headers | show |
On 10/28/2015 11:06 PM, Don Brace wrote: > From: Kevin Barnett <kevin.barnett@pmcs.com> > > Reviewed-by: Scott Teel <scott.teel@pmcs.com> > Reviewed-by: Justin Lindley <justin.lindley@pmcs.com> > Reviewed-by: Kevin Barnett <kevin.barnett@pmcs.com> > Signed-off-by: Don Brace <don.brace@pmcs.com> > --- > drivers/scsi/hpsa.c | 535 +++++++++++++++++++++++++++++++++++++++++++++-- > drivers/scsi/hpsa.h | 27 ++ > drivers/scsi/hpsa_cmd.h | 14 + > 3 files changed, 555 insertions(+), 21 deletions(-) > Reviewed-by: Hannes Reinecke <hare@suse.de> Cheers, Hannes
On 28.10.2015 23:06, Don Brace wrote: > From: Kevin Barnett <kevin.barnett@pmcs.com> > > Reviewed-by: Scott Teel <scott.teel@pmcs.com> > Reviewed-by: Justin Lindley <justin.lindley@pmcs.com> > Reviewed-by: Kevin Barnett <kevin.barnett@pmcs.com> > Signed-off-by: Don Brace <don.brace@pmcs.com> Reviewed-by: Tomas Henzl <thenzl@redhat.com> Tomas -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
> On Oct 28, 2015, at 5:06 PM, Don Brace <don.brace@pmcs.com> wrote: > > From: Kevin Barnett <kevin.barnett@pmcs.com> > > Reviewed-by: Scott Teel <scott.teel@pmcs.com> > Reviewed-by: Justin Lindley <justin.lindley@pmcs.com> > Reviewed-by: Kevin Barnett <kevin.barnett@pmcs.com> > Signed-off-by: Don Brace <don.brace@pmcs.com> > --- > drivers/scsi/hpsa.c | 535 +++++++++++++++++++++++++++++++++++++++++++++-- > drivers/scsi/hpsa.h | 27 ++ > drivers/scsi/hpsa_cmd.h | 14 + > 3 files changed, 555 insertions(+), 21 deletions(-) > > diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c > index 56526312..ca38a00 100644 > --- a/drivers/scsi/hpsa.c > +++ b/drivers/scsi/hpsa.c > @@ -41,6 +41,7 @@ > #include <scsi/scsi_host.h> > #include <scsi/scsi_tcq.h> > #include <scsi/scsi_eh.h> > +#include <scsi/scsi_transport_sas.h> > #include <scsi/scsi_dbg.h> > #include <linux/cciss_ioctl.h> > #include <linux/string.h> > @@ -205,6 +206,16 @@ static struct board_type products[] = { > {0xFFFF103C, "Unknown Smart Array", &SA5_access}, > }; > > +static struct scsi_transport_template *hpsa_sas_transport_template; > +static int hpsa_add_sas_host(struct ctlr_info *h); > +static void hpsa_delete_sas_host(struct ctlr_info *h); > +static int hpsa_add_sas_device(struct hpsa_sas_node *hpsa_sas_node, > + struct hpsa_scsi_dev_t *device); > +static void hpsa_remove_sas_device(struct hpsa_scsi_dev_t *device); > +static struct hpsa_scsi_dev_t > + *hpsa_find_device_by_sas_rphy(struct ctlr_info *h, > + struct sas_rphy *rphy); > + > #define SCSI_CMD_BUSY ((struct scsi_cmnd *)&hpsa_cmd_busy) > static const struct scsi_cmnd hpsa_cmd_busy; > #define SCSI_CMD_IDLE ((struct scsi_cmnd *)&hpsa_cmd_idle) > @@ -277,6 +288,8 @@ static void hpsa_command_resubmit_worker(struct work_struct *work); > static u32 lockup_detected(struct ctlr_info *h); > static int detect_controller_lockup(struct ctlr_info *h); > static void hpsa_disable_rld_caching(struct ctlr_info *h); > +static inline int hpsa_scsi_do_report_phys_luns(struct ctlr_info *h, > + struct ReportExtendedLUNdata *buf, int bufsize); > static int hpsa_luns_changed(struct ctlr_info *h); > > static inline struct ctlr_info *sdev_to_hba(struct scsi_device *sdev) > @@ -1696,8 +1709,12 @@ static int hpsa_add_device(struct ctlr_info *h, struct hpsa_scsi_dev_t *device) > { > int rc = 0; > > - rc = scsi_add_device(h->scsi_host, device->bus, > + if (is_logical_device(device)) /* RAID */ > + rc = scsi_add_device(h->scsi_host, device->bus, > device->target, device->lun); > + else /* HBA */ > + rc = hpsa_add_sas_device(h->sas_host, device); > + > return rc; > } > > @@ -1706,21 +1723,23 @@ static void hpsa_remove_device(struct ctlr_info *h, > { > struct scsi_device *sdev = NULL; > > - sdev = scsi_device_lookup(h->scsi_host, device->bus, > + if (is_logical_device(device)) { /* RAID */ > + sdev = scsi_device_lookup(h->scsi_host, device->bus, > device->target, device->lun); > - > - if (sdev) { > - scsi_remove_device(sdev); > - scsi_device_put(sdev); > - } else { > - /* > - * We don't expect to get here. Future commands > - * to this device will get a selection timeout as > - * if the device were gone. > - */ > - hpsa_show_dev_msg(KERN_WARNING, h, device, > + if (sdev) { > + scsi_remove_device(sdev); > + scsi_device_put(sdev); > + } else { > + /* > + * We don't expect to get here. Future commands > + * to this device will get a selection timeout as > + * if the device were gone. > + */ > + hpsa_show_dev_msg(KERN_WARNING, h, device, > "didn't find device for removal."); > - } > + } > + } else /* HBA */ > + hpsa_remove_sas_device(device); > } > > static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, > @@ -1915,11 +1934,24 @@ static int hpsa_slave_alloc(struct scsi_device *sdev) > > h = sdev_to_hba(sdev); > spin_lock_irqsave(&h->devlock, flags); > - sd = lookup_hpsa_scsi_dev(h, sdev_channel(sdev), > - sdev_id(sdev), sdev->lun); > - if (likely(sd)) { > + if (sdev_channel(sdev) == HPSA_PHYSICAL_DEVICE_BUS) { > + struct scsi_target *starget; > + struct sas_rphy *rphy; > + > + starget = scsi_target(sdev); > + rphy = target_to_rphy(starget); > + sd = hpsa_find_device_by_sas_rphy(h, rphy); > + if (sd) { > + sd->target = sdev_id(sdev); > + sd->lun = sdev->lun; > + } > + } else > + sd = lookup_hpsa_scsi_dev(h, sdev_channel(sdev), > + sdev_id(sdev), sdev->lun); > + > + if (sd && sd->expose_device) { > atomic_set(&sd->ioaccel_cmds_out, 0); > - sdev->hostdata = sd->expose_device ? sd : NULL; > + sdev->hostdata = sd; > } else > sdev->hostdata = NULL; > spin_unlock_irqrestore(&h->devlock, flags); > @@ -3069,6 +3101,38 @@ out: > return rc; > } > > +static int hpsa_bmic_sense_subsystem_information(struct ctlr_info *h, > + unsigned char scsi3addr[], u16 bmic_device_index, > + struct bmic_sense_subsystem_info *buf, size_t bufsize) > +{ > + int rc = IO_OK; > + struct CommandList *c; > + struct ErrorInfo *ei; > + > + c = cmd_alloc(h); > + > + rc = fill_cmd(c, BMIC_SENSE_SUBSYSTEM_INFORMATION, h, buf, bufsize, > + 0, RAID_CTLR_LUNID, TYPE_CMD); > + if (rc) > + goto out; > + > + c->Request.CDB[2] = bmic_device_index & 0xff; > + c->Request.CDB[9] = (bmic_device_index >> 8) & 0xff; > + > + rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, > + PCI_DMA_FROMDEVICE, NO_TIMEOUT); > + if (rc) > + goto out; > + ei = c->err_info; > + if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) { > + hpsa_scsi_interpret_error(h, c); > + rc = -1; > + } > +out: > + cmd_free(h, c); > + return rc; > +} > + > static int hpsa_bmic_id_controller(struct ctlr_info *h, > struct bmic_identify_controller *buf, size_t bufsize) > { > @@ -3097,7 +3161,6 @@ out: > return rc; > } > > - > static int hpsa_bmic_id_physical_device(struct ctlr_info *h, > unsigned char scsi3addr[], u16 bmic_device_index, > struct bmic_identify_physical_device *buf, size_t bufsize) > @@ -3124,9 +3187,64 @@ static int hpsa_bmic_id_physical_device(struct ctlr_info *h, > } > out: > cmd_free(h, c); > + > return rc; > } > > +static u64 hpsa_get_sas_address_from_report_physical(struct ctlr_info *h, > + unsigned char *scsi3addr) > +{ > + struct ReportExtendedLUNdata *physdev; > + u32 nphysicals; > + u64 sa = 0; > + int i; > + > + physdev = kzalloc(sizeof(*physdev), GFP_KERNEL); > + if (!physdev) > + return 0; > + > + if (hpsa_scsi_do_report_phys_luns(h, physdev, sizeof(*physdev))) { > + dev_err(&h->pdev->dev, "report physical LUNs failed.\n"); > + kfree(physdev); > + return 0; > + } > + nphysicals = get_unaligned_be32(physdev->LUNListLength) / 24; > + > + for (i = 0; i < nphysicals; i++) > + if (!memcmp(&physdev->LUN[i].lunid[0], scsi3addr, 8)) > + sa = get_unaligned_be64(&physdev->LUN[i].wwid[0]); Don't you want to break out here if you found a match? > + > + kfree(physdev); > + > + return sa; > +} > + > +static void hpsa_get_sas_address(struct ctlr_info *h, unsigned char *scsi3addr, > + struct hpsa_scsi_dev_t *dev) > +{ > + int rc; > + u64 sa = 0; > + > + if (is_hba_lunid(scsi3addr)) { > + struct bmic_sense_subsystem_info *ssi; > + > + ssi = kzalloc(sizeof(*ssi), GFP_KERNEL); What happens if this allocation fails? If the I/O can succeed without the DMA buffer then you will run into trouble when deriving sa. > + > + rc = hpsa_bmic_sense_subsystem_information(h, > + scsi3addr, 0, ssi, sizeof(*ssi)); > + if (rc == 0) { > + sa = get_unaligned_be64(ssi->primary_world_wide_id); > + h->sas_address = sa; > + } > + > + kfree(ssi); > + } else > + sa = hpsa_get_sas_address_from_report_physical(h, scsi3addr); > + > + dev->sas_address = sa; > +} > + > +/* Get a device id from inquiry page 0x83 */ > static int hpsa_vpd_page_supported(struct ctlr_info *h, > unsigned char scsi3addr[], u8 page) > { > @@ -3961,6 +4079,13 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) > else > this_device->expose_device = 1; > > + > + /* > + * Get the SAS address for physical devices that are exposed. > + */ > + if (this_device->physical_device && this_device->expose_device) > + hpsa_get_sas_address(h, lunaddrbytes, this_device); > + > switch (this_device->devtype) { > case TYPE_ROM: > /* We don't *really* support actual CD-ROM devices, > @@ -4006,6 +4131,10 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) > if (ncurrent >= HPSA_MAX_DEVICES) > break; > } > + > + if (h->sas_host == NULL) > + hpsa_add_sas_host(h); > + > adjust_hpsa_scsi_table(h, hostno, currentsd, ncurrent); > out: > kfree(tmpdevice); > @@ -5137,6 +5266,7 @@ static int hpsa_scsi_host_alloc(struct ctlr_info *h) > sh->can_queue = h->nr_cmds - HPSA_NRESERVED_CMDS; > sh->cmd_per_lun = sh->can_queue; > sh->sg_tablesize = h->maxsgentries; > + sh->transportt = hpsa_sas_transport_template; > sh->hostdata[0] = (unsigned long) h; > sh->irq = h->intr[h->intr_mode]; > sh->unique_id = sh->irq; > @@ -6485,6 +6615,16 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, > c->Request.CDB[7] = (size >> 16) & 0xFF; > c->Request.CDB[8] = (size >> 8) & 0XFF; > break; > + case BMIC_SENSE_SUBSYSTEM_INFORMATION: > + c->Request.CDBLen = 10; > + c->Request.type_attr_dir = > + TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ); > + c->Request.Timeout = 0; > + c->Request.CDB[0] = BMIC_READ; > + c->Request.CDB[6] = BMIC_SENSE_SUBSYSTEM_INFORMATION; > + c->Request.CDB[7] = (size >> 16) & 0xFF; > + c->Request.CDB[8] = (size >> 8) & 0XFF; > + break; > case BMIC_IDENTIFY_CONTROLLER: > c->Request.CDBLen = 10; > c->Request.type_attr_dir = > @@ -6501,7 +6641,6 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, > c->Request.CDB[8] = (size >> 8) & 0XFF; > c->Request.CDB[9] = 0; > break; > - > default: > dev_warn(&h->pdev->dev, "unknown command 0x%c\n", cmd); > BUG(); > @@ -8618,6 +8757,9 @@ static void hpsa_remove_one(struct pci_dev *pdev) > free_percpu(h->lockup_detected); /* init_one 2 */ > h->lockup_detected = NULL; /* init_one 2 */ > /* (void) pci_disable_pcie_error_reporting(pdev); */ /* init_one 1 */ > + > + hpsa_delete_sas_host(h); > + > kfree(h); /* init_one 1 */ > } > > @@ -9080,18 +9222,369 @@ static void hpsa_drain_accel_commands(struct ctlr_info *h) > } while (1); > } > > +static struct hpsa_sas_phy *hpsa_alloc_sas_phy( > + struct hpsa_sas_port *hpsa_sas_port) > +{ > + struct hpsa_sas_phy *hpsa_sas_phy; > + struct sas_phy *phy; > + > + hpsa_sas_phy = kzalloc(sizeof(*hpsa_sas_phy), GFP_KERNEL); > + if (!hpsa_sas_phy) > + return NULL; > + > + phy = sas_phy_alloc(hpsa_sas_port->parent_node->parent_dev, > + hpsa_sas_port->next_phy_index); > + if (!phy) { > + kfree(hpsa_sas_phy); > + return NULL; > + } > + > + hpsa_sas_port->next_phy_index++; > + hpsa_sas_phy->phy = phy; > + hpsa_sas_phy->parent_port = hpsa_sas_port; > + > + return hpsa_sas_phy; > +} > + > +static void hpsa_free_sas_phy(struct hpsa_sas_phy *hpsa_sas_phy) > +{ > + struct sas_phy *phy = hpsa_sas_phy->phy; > + > + sas_port_delete_phy(hpsa_sas_phy->parent_port->port, phy); > + sas_phy_free(phy); > + if (hpsa_sas_phy->added_to_port) > + list_del(&hpsa_sas_phy->phy_list_entry); > + kfree(hpsa_sas_phy); > +} > + > +static int hpsa_sas_port_add_phy(struct hpsa_sas_phy *hpsa_sas_phy) > +{ > + int rc; > + struct hpsa_sas_port *hpsa_sas_port; > + struct sas_phy *phy; > + struct sas_identify *identify; > + > + hpsa_sas_port = hpsa_sas_phy->parent_port; > + phy = hpsa_sas_phy->phy; > + > + identify = &phy->identify; > + memset(identify, 0, sizeof(*identify)); > + identify->sas_address = hpsa_sas_port->sas_address; > + identify->device_type = SAS_END_DEVICE; > + identify->initiator_port_protocols = SAS_PROTOCOL_STP; > + identify->target_port_protocols = SAS_PROTOCOL_STP; > + phy->minimum_linkrate_hw = SAS_LINK_RATE_UNKNOWN; > + phy->maximum_linkrate_hw = SAS_LINK_RATE_UNKNOWN; > + phy->minimum_linkrate = SAS_LINK_RATE_UNKNOWN; > + phy->maximum_linkrate = SAS_LINK_RATE_UNKNOWN; > + phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN; > + > + rc = sas_phy_add(hpsa_sas_phy->phy); > + if (rc) > + return rc; > + > + sas_port_add_phy(hpsa_sas_port->port, hpsa_sas_phy->phy); > + list_add_tail(&hpsa_sas_phy->phy_list_entry, > + &hpsa_sas_port->phy_list_head); > + hpsa_sas_phy->added_to_port = true; > + > + return 0; > +} > + > +static int > + hpsa_sas_port_add_rphy(struct hpsa_sas_port *hpsa_sas_port, > + struct sas_rphy *rphy) > +{ > + struct sas_identify *identify; > + > + identify = &rphy->identify; > + identify->sas_address = hpsa_sas_port->sas_address; > + identify->initiator_port_protocols = SAS_PROTOCOL_STP; > + identify->target_port_protocols = SAS_PROTOCOL_STP; > + > + return sas_rphy_add(rphy); > +} > + > +static struct hpsa_sas_port > + *hpsa_alloc_sas_port(struct hpsa_sas_node *hpsa_sas_node, > + u64 sas_address) > +{ > + int rc; > + struct hpsa_sas_port *hpsa_sas_port; > + struct sas_port *port; > + > + hpsa_sas_port = kzalloc(sizeof(*hpsa_sas_port), GFP_KERNEL); > + if (!hpsa_sas_port) > + return NULL; > + > + INIT_LIST_HEAD(&hpsa_sas_port->phy_list_head); > + hpsa_sas_port->parent_node = hpsa_sas_node; > + > + port = sas_port_alloc_num(hpsa_sas_node->parent_dev); > + if (!port) > + goto free_hpsa_port; > + > + rc = sas_port_add(port); > + if (rc) > + goto free_sas_port; > + > + hpsa_sas_port->port = port; > + hpsa_sas_port->sas_address = sas_address; > + list_add_tail(&hpsa_sas_port->port_list_entry, > + &hpsa_sas_node->port_list_head); > + > + return hpsa_sas_port; > + > +free_sas_port: > + sas_port_free(port); > +free_hpsa_port: > + kfree(hpsa_sas_port); > + > + return NULL; > +} > + > +static void hpsa_free_sas_port(struct hpsa_sas_port *hpsa_sas_port) > +{ > + struct hpsa_sas_phy *hpsa_sas_phy; > + struct hpsa_sas_phy *next; > + > + list_for_each_entry_safe(hpsa_sas_phy, next, > + &hpsa_sas_port->phy_list_head, phy_list_entry) > + hpsa_free_sas_phy(hpsa_sas_phy); > + > + sas_port_delete(hpsa_sas_port->port); > + list_del(&hpsa_sas_port->port_list_entry); > + kfree(hpsa_sas_port); > +} > + > +static struct hpsa_sas_node *hpsa_alloc_sas_node(struct device *parent_dev) > +{ > + struct hpsa_sas_node *hpsa_sas_node; > + > + hpsa_sas_node = kzalloc(sizeof(*hpsa_sas_node), GFP_KERNEL); > + if (hpsa_sas_node) { > + hpsa_sas_node->parent_dev = parent_dev; > + INIT_LIST_HEAD(&hpsa_sas_node->port_list_head); > + } > + > + return hpsa_sas_node; > +} > + > +static void hpsa_free_sas_node(struct hpsa_sas_node *hpsa_sas_node) > +{ > + struct hpsa_sas_port *hpsa_sas_port; > + struct hpsa_sas_port *next; > + > + if (!hpsa_sas_node) > + return; > + > + list_for_each_entry_safe(hpsa_sas_port, next, > + &hpsa_sas_node->port_list_head, port_list_entry) > + hpsa_free_sas_port(hpsa_sas_port); > + > + kfree(hpsa_sas_node); > +} > + > +static struct hpsa_scsi_dev_t > + *hpsa_find_device_by_sas_rphy(struct ctlr_info *h, > + struct sas_rphy *rphy) > +{ > + int i; > + struct hpsa_scsi_dev_t *device; > + > + for (i = 0; i < h->ndevices; i++) { > + device = h->dev[i]; > + if (!device->sas_port) > + continue; > + if (device->sas_port->rphy == rphy) > + return device; > + } > + > + return NULL; > +} > + > +static int hpsa_add_sas_host(struct ctlr_info *h) > +{ > + int rc; > + struct device *parent_dev; > + struct hpsa_sas_node *hpsa_sas_node; > + struct hpsa_sas_port *hpsa_sas_port; > + struct hpsa_sas_phy *hpsa_sas_phy; > + > + parent_dev = &h->scsi_host->shost_gendev; > + > + hpsa_sas_node = hpsa_alloc_sas_node(parent_dev); > + if (!hpsa_sas_node) > + return -ENOMEM; > + > + hpsa_sas_port = hpsa_alloc_sas_port(hpsa_sas_node, h->sas_address); > + if (!hpsa_sas_port) { > + rc = -ENODEV; > + goto free_sas_node; > + } > + > + hpsa_sas_phy = hpsa_alloc_sas_phy(hpsa_sas_port); > + if (!hpsa_sas_phy) { > + rc = -ENODEV; > + goto free_sas_port; > + } > + > + rc = hpsa_sas_port_add_phy(hpsa_sas_phy); > + if (rc) > + goto free_sas_phy; > + > + h->sas_host = hpsa_sas_node; > + > + return 0; > + > +free_sas_phy: > + hpsa_free_sas_phy(hpsa_sas_phy); > +free_sas_port: > + hpsa_free_sas_port(hpsa_sas_port); > +free_sas_node: > + hpsa_free_sas_node(hpsa_sas_node); > + > + return rc; > +} > + > +static void hpsa_delete_sas_host(struct ctlr_info *h) > +{ > + hpsa_free_sas_node(h->sas_host); > +} > + > +static int hpsa_add_sas_device(struct hpsa_sas_node *hpsa_sas_node, > + struct hpsa_scsi_dev_t *device) > +{ > + int rc; > + struct hpsa_sas_port *hpsa_sas_port; > + struct sas_rphy *rphy; > + > + hpsa_sas_port = hpsa_alloc_sas_port(hpsa_sas_node, device->sas_address); > + if (!hpsa_sas_port) > + return -ENOMEM; > + > + rphy = sas_end_device_alloc(hpsa_sas_port->port); > + if (!rphy) { > + rc = -ENODEV; > + goto free_sas_port; > + } > + > + hpsa_sas_port->rphy = rphy; > + device->sas_port = hpsa_sas_port; > + > + rc = hpsa_sas_port_add_rphy(hpsa_sas_port, rphy); > + if (rc) > + goto free_sas_port; > + > + return 0; > + > +free_sas_port: > + hpsa_free_sas_port(hpsa_sas_port); > + device->sas_port = NULL; > + > + return rc; > +} > + > +static void hpsa_remove_sas_device(struct hpsa_scsi_dev_t *device) > +{ > + if (device->sas_port) { > + hpsa_free_sas_port(device->sas_port); > + device->sas_port = NULL; > + } > +} > + > +static int > +hpsa_sas_get_linkerrors(struct sas_phy *phy) > +{ > + return 0; > +} > + > +static int > +hpsa_sas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier) > +{ > + return 0; > +} > + > +static int > +hpsa_sas_get_bay_identifier(struct sas_rphy *rphy) > +{ > + return -ENXIO; > +} > + > +static int > +hpsa_sas_phy_reset(struct sas_phy *phy, int hard_reset) > +{ > + return 0; > +} > + > +static int > +hpsa_sas_phy_enable(struct sas_phy *phy, int enable) > +{ > + return 0; > +} > + > +static int > +hpsa_sas_phy_setup(struct sas_phy *phy) > +{ > + return 0; > +} > + > +static void > +hpsa_sas_phy_release(struct sas_phy *phy) > +{ > +} > + > +static int > +hpsa_sas_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates) > +{ > + return -EINVAL; > +} > + > +/* SMP = Serial Management Protocol */ > +static int > +hpsa_sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, > +struct request *req) > +{ > + return -EINVAL; > +} > + > +static struct sas_function_template hpsa_sas_transport_functions = { > + .get_linkerrors = hpsa_sas_get_linkerrors, > + .get_enclosure_identifier = hpsa_sas_get_enclosure_identifier, > + .get_bay_identifier = hpsa_sas_get_bay_identifier, > + .phy_reset = hpsa_sas_phy_reset, > + .phy_enable = hpsa_sas_phy_enable, > + .phy_setup = hpsa_sas_phy_setup, > + .phy_release = hpsa_sas_phy_release, > + .set_phy_speed = hpsa_sas_phy_speed, > + .smp_handler = hpsa_sas_smp_handler, > +}; > + > /* > * This is it. Register the PCI driver information for the cards we control > * the OS will call our registered routines when it finds one of our cards. > */ > static int __init hpsa_init(void) > { > - return pci_register_driver(&hpsa_pci_driver); > + int rc; > + > + hpsa_sas_transport_template = > + sas_attach_transport(&hpsa_sas_transport_functions); > + if (!hpsa_sas_transport_template) > + return -ENODEV; > + > + rc = pci_register_driver(&hpsa_pci_driver); > + > + if (rc) > + sas_release_transport(hpsa_sas_transport_template); > + > + return rc; > } > > static void __exit hpsa_cleanup(void) > { > pci_unregister_driver(&hpsa_pci_driver); > + sas_release_transport(hpsa_sas_transport_template); > } > > static void __attribute__((unused)) verify_offsets(void) > diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h > index 6c82d3c..7847405 100644 > --- a/drivers/scsi/hpsa.h > +++ b/drivers/scsi/hpsa.h > @@ -33,6 +33,29 @@ struct access_method { > unsigned long (*command_completed)(struct ctlr_info *h, u8 q); > }; > > +/* for SAS hosts and SAS expanders */ > +struct hpsa_sas_node { > + struct device *parent_dev; > + struct list_head port_list_head; > +}; > + > +struct hpsa_sas_port { > + struct list_head port_list_entry; > + u64 sas_address; > + struct sas_port *port; > + int next_phy_index; > + struct list_head phy_list_head; > + struct hpsa_sas_node *parent_node; > + struct sas_rphy *rphy; > +}; > + > +struct hpsa_sas_phy { > + struct list_head phy_list_entry; > + struct sas_phy *phy; > + struct hpsa_sas_port *parent_port; > + bool added_to_port; > +}; > + > struct hpsa_scsi_dev_t { > unsigned int devtype; > int bus, target, lun; /* as presented to the OS */ > @@ -41,6 +64,7 @@ struct hpsa_scsi_dev_t { > u8 expose_device; > #define RAID_CTLR_LUNID "\0\0\0\0\0\0\0\0" > unsigned char device_id[16]; /* from inquiry pg. 0x83 */ > + u64 sas_address; > unsigned char vendor[8]; /* bytes 8-15 of inquiry data */ > unsigned char model[16]; /* bytes 16-31 of inquiry data */ > unsigned char raid_level; /* from inquiry page 0xC1 */ > @@ -77,6 +101,7 @@ struct hpsa_scsi_dev_t { > struct hpsa_scsi_dev_t *phys_disk[RAID_MAP_MAX_ENTRIES]; > int nphysical_disks; > int supports_aborts; > + struct hpsa_sas_port *sas_port; > int external; /* 1-from external array 0-not <0-unknown */ > }; > > @@ -134,6 +159,7 @@ struct ctlr_info { > char *product_name; > struct pci_dev *pdev; > u32 board_id; > + u64 sas_address; > void __iomem *vaddr; > unsigned long paddr; > int nr_cmds; /* Number of commands allowed on this controller */ > @@ -272,6 +298,7 @@ struct ctlr_info { > wait_queue_head_t event_sync_wait_queue; > struct mutex reset_mutex; > u8 reset_in_progress; > + struct hpsa_sas_node *sas_host; > }; > > struct offline_device_entry { > diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h > index 4910344..d92ef0d 100644 > --- a/drivers/scsi/hpsa_cmd.h > +++ b/drivers/scsi/hpsa_cmd.h > @@ -290,6 +290,7 @@ struct SenseSubsystem_info { > #define BMIC_SET_DIAG_OPTIONS 0xF4 > #define BMIC_SENSE_DIAG_OPTIONS 0xF5 > #define HPSA_DIAG_OPTS_DISABLE_RLD_CACHING 0x40000000 > +#define BMIC_SENSE_SUBSYSTEM_INFORMATION 0x66 > > /* Command List Structure */ > union SCSI3Addr { > @@ -828,5 +829,18 @@ struct bmic_identify_physical_device { > u8 padding[112]; > }; > > +struct bmic_sense_subsystem_info { > + u8 primary_slot_number; > + u8 reserved[3]; > + u8 chasis_serial_number[32]; > + u8 primary_world_wide_id[8]; > + u8 primary_array_serial_number[32]; /* NULL terminated */ > + u8 primary_cache_serial_number[32]; /* NULL terminated */ > + u8 reserved_2[8]; > + u8 secondary_array_serial_number[32]; > + u8 secondary_cache_serial_number[32]; > + u8 pad[332]; > +}; > + > #pragma pack() > #endif /* HPSA_CMD_H */ > > -- > To unsubscribe from this list: send the line "unsubscribe linux-scsi" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html > -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 10/30/2015 03:07 PM, Matthew R. Ochs wrote: >> On Oct 28, 2015, at 5:06 PM, Don Brace <don.brace@pmcs.com> wrote: >> >> From: Kevin Barnett <kevin.barnett@pmcs.com> >> >> Reviewed-by: Scott Teel <scott.teel@pmcs.com> >> Reviewed-by: Justin Lindley <justin.lindley@pmcs.com> >> Reviewed-by: Kevin Barnett <kevin.barnett@pmcs.com> >> Signed-off-by: Don Brace <don.brace@pmcs.com> >> --- >> drivers/scsi/hpsa.c | 535 +++++++++++++++++++++++++++++++++++++++++++++-- >> drivers/scsi/hpsa.h | 27 ++ >> drivers/scsi/hpsa_cmd.h | 14 + >> 3 files changed, 555 insertions(+), 21 deletions(-) >> >> diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c >> index 56526312..ca38a00 100644 >> --- a/drivers/scsi/hpsa.c >> +++ b/drivers/scsi/hpsa.c >> @@ -41,6 +41,7 @@ >> >> +static u64 hpsa_get_sas_address_from_report_physical(struct ctlr_info *h, >> + unsigned char *scsi3addr) >> +{ >> + struct ReportExtendedLUNdata *physdev; >> + u32 nphysicals; >> + u64 sa = 0; >> + int i; >> + >> + physdev = kzalloc(sizeof(*physdev), GFP_KERNEL); >> + if (!physdev) >> + return 0; >> + >> + if (hpsa_scsi_do_report_phys_luns(h, physdev, sizeof(*physdev))) { >> + dev_err(&h->pdev->dev, "report physical LUNs failed.\n"); >> + kfree(physdev); >> + return 0; >> + } >> + nphysicals = get_unaligned_be32(physdev->LUNListLength) / 24; >> + >> + for (i = 0; i < nphysicals; i++) >> + if (!memcmp(&physdev->LUN[i].lunid[0], scsi3addr, 8)) >> + sa = get_unaligned_be64(&physdev->LUN[i].wwid[0]); > Don't you want to break out here if you found a match? Agreed. > >> + >> + kfree(physdev); >> + >> + return sa; >> +} >> + >> +static void hpsa_get_sas_address(struct ctlr_info *h, unsigned char *scsi3addr, >> + struct hpsa_scsi_dev_t *dev) >> +{ >> + int rc; >> + u64 sa = 0; >> + >> + if (is_hba_lunid(scsi3addr)) { >> + struct bmic_sense_subsystem_info *ssi; >> + >> + ssi = kzalloc(sizeof(*ssi), GFP_KERNEL); > What happens if this allocation fails? If the I/O can succeed without the > DMA buffer then you will run into trouble when deriving sa. Added check for NULL. > > -- > To unsubscribe from this list: send the line "unsubscribe linux-scsi" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
> On Oct 30, 2015, at 5:00 PM, Don Brace <brace77070@gmail.com> wrote: > On 10/30/2015 03:07 PM, Matthew R. Ochs wrote: >>> On Oct 28, 2015, at 5:06 PM, Don Brace <don.brace@pmcs.com> wrote: >>> >>> From: Kevin Barnett <kevin.barnett@pmcs.com> >>> >>> Reviewed-by: Scott Teel <scott.teel@pmcs.com> >>> Reviewed-by: Justin Lindley <justin.lindley@pmcs.com> >>> Reviewed-by: Kevin Barnett <kevin.barnett@pmcs.com> >>> Signed-off-by: Don Brace <don.brace@pmcs.com> >>> --- >>> drivers/scsi/hpsa.c | 535 +++++++++++++++++++++++++++++++++++++++++++++-- >>> drivers/scsi/hpsa.h | 27 ++ >>> drivers/scsi/hpsa_cmd.h | 14 + >>> 3 files changed, 555 insertions(+), 21 deletions(-) >>> >>> diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c >>> index 56526312..ca38a00 100644 >>> --- a/drivers/scsi/hpsa.c >>> +++ b/drivers/scsi/hpsa.c >>> @@ -41,6 +41,7 @@ >>> >>> +static u64 hpsa_get_sas_address_from_report_physical(struct ctlr_info *h, >>> + unsigned char *scsi3addr) >>> +{ >>> + struct ReportExtendedLUNdata *physdev; >>> + u32 nphysicals; >>> + u64 sa = 0; >>> + int i; >>> + >>> + physdev = kzalloc(sizeof(*physdev), GFP_KERNEL); >>> + if (!physdev) >>> + return 0; >>> + >>> + if (hpsa_scsi_do_report_phys_luns(h, physdev, sizeof(*physdev))) { >>> + dev_err(&h->pdev->dev, "report physical LUNs failed.\n"); >>> + kfree(physdev); >>> + return 0; >>> + } >>> + nphysicals = get_unaligned_be32(physdev->LUNListLength) / 24; >>> + >>> + for (i = 0; i < nphysicals; i++) >>> + if (!memcmp(&physdev->LUN[i].lunid[0], scsi3addr, 8)) >>> + sa = get_unaligned_be64(&physdev->LUN[i].wwid[0]); >> Don't you want to break out here if you found a match? > Agreed. >> >>> + >>> + kfree(physdev); >>> + >>> + return sa; >>> +} >>> + >>> +static void hpsa_get_sas_address(struct ctlr_info *h, unsigned char *scsi3addr, >>> + struct hpsa_scsi_dev_t *dev) >>> +{ >>> + int rc; >>> + u64 sa = 0; >>> + >>> + if (is_hba_lunid(scsi3addr)) { >>> + struct bmic_sense_subsystem_info *ssi; >>> + >>> + ssi = kzalloc(sizeof(*ssi), GFP_KERNEL); >> What happens if this allocation fails? If the I/O can succeed without the >> DMA buffer then you will run into trouble when deriving sa. > Added check for NULL. With these changes Reviewed-by: Matthew R. Ochs <mrochs@linux.vnet.ibm.com> -- To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Hi Kevin, [auto build test ERROR on scsi/for-next -- if it's inappropriate base, please suggest rules for selecting the more suitable base] url: https://github.com/0day-ci/linux/commits/Don-Brace/hpsa-updates/20151029-061230 config: i386-randconfig-b0-11030633 (attached as .config) reproduce: # save the attached .config to linux build tree make ARCH=i386 All errors (new ones prefixed by >>): drivers/built-in.o: In function `hpsa_free_sas_phy': >> hpsa.c:(.text+0x11439a): undefined reference to `sas_port_delete_phy' >> hpsa.c:(.text+0x1143a1): undefined reference to `sas_phy_free' drivers/built-in.o: In function `hpsa_free_sas_port': >> hpsa.c:(.text+0x1143e5): undefined reference to `sas_port_delete' drivers/built-in.o: In function `hpsa_alloc_sas_port': >> hpsa.c:(.text+0x11457a): undefined reference to `sas_port_alloc_num' >> hpsa.c:(.text+0x114585): undefined reference to `sas_port_add' >> hpsa.c:(.text+0x1145b0): undefined reference to `sas_port_free' drivers/built-in.o: In function `hpsa_scan_start': >> hpsa.c:(.text+0x11a725): undefined reference to `sas_phy_alloc' >> hpsa.c:(.text+0x11a7c2): undefined reference to `sas_phy_add' >> hpsa.c:(.text+0x11a7d4): undefined reference to `sas_port_add_phy' >> hpsa.c:(.text+0x11b2f9): undefined reference to `sas_end_device_alloc' >> hpsa.c:(.text+0x11b331): undefined reference to `sas_rphy_add' drivers/built-in.o: In function `hpsa_init': >> hpsa.c:(.init.text+0xb4b9): undefined reference to `sas_attach_transport' >> hpsa.c:(.init.text+0xb4ea): undefined reference to `sas_release_transport' drivers/built-in.o: In function `hpsa_cleanup': >> hpsa.c:(.exit.text+0xf72): undefined reference to `sas_release_transport' --- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c index 56526312..ca38a00 100644 --- a/drivers/scsi/hpsa.c +++ b/drivers/scsi/hpsa.c @@ -41,6 +41,7 @@ #include <scsi/scsi_host.h> #include <scsi/scsi_tcq.h> #include <scsi/scsi_eh.h> +#include <scsi/scsi_transport_sas.h> #include <scsi/scsi_dbg.h> #include <linux/cciss_ioctl.h> #include <linux/string.h> @@ -205,6 +206,16 @@ static struct board_type products[] = { {0xFFFF103C, "Unknown Smart Array", &SA5_access}, }; +static struct scsi_transport_template *hpsa_sas_transport_template; +static int hpsa_add_sas_host(struct ctlr_info *h); +static void hpsa_delete_sas_host(struct ctlr_info *h); +static int hpsa_add_sas_device(struct hpsa_sas_node *hpsa_sas_node, + struct hpsa_scsi_dev_t *device); +static void hpsa_remove_sas_device(struct hpsa_scsi_dev_t *device); +static struct hpsa_scsi_dev_t + *hpsa_find_device_by_sas_rphy(struct ctlr_info *h, + struct sas_rphy *rphy); + #define SCSI_CMD_BUSY ((struct scsi_cmnd *)&hpsa_cmd_busy) static const struct scsi_cmnd hpsa_cmd_busy; #define SCSI_CMD_IDLE ((struct scsi_cmnd *)&hpsa_cmd_idle) @@ -277,6 +288,8 @@ static void hpsa_command_resubmit_worker(struct work_struct *work); static u32 lockup_detected(struct ctlr_info *h); static int detect_controller_lockup(struct ctlr_info *h); static void hpsa_disable_rld_caching(struct ctlr_info *h); +static inline int hpsa_scsi_do_report_phys_luns(struct ctlr_info *h, + struct ReportExtendedLUNdata *buf, int bufsize); static int hpsa_luns_changed(struct ctlr_info *h); static inline struct ctlr_info *sdev_to_hba(struct scsi_device *sdev) @@ -1696,8 +1709,12 @@ static int hpsa_add_device(struct ctlr_info *h, struct hpsa_scsi_dev_t *device) { int rc = 0; - rc = scsi_add_device(h->scsi_host, device->bus, + if (is_logical_device(device)) /* RAID */ + rc = scsi_add_device(h->scsi_host, device->bus, device->target, device->lun); + else /* HBA */ + rc = hpsa_add_sas_device(h->sas_host, device); + return rc; } @@ -1706,21 +1723,23 @@ static void hpsa_remove_device(struct ctlr_info *h, { struct scsi_device *sdev = NULL; - sdev = scsi_device_lookup(h->scsi_host, device->bus, + if (is_logical_device(device)) { /* RAID */ + sdev = scsi_device_lookup(h->scsi_host, device->bus, device->target, device->lun); - - if (sdev) { - scsi_remove_device(sdev); - scsi_device_put(sdev); - } else { - /* - * We don't expect to get here. Future commands - * to this device will get a selection timeout as - * if the device were gone. - */ - hpsa_show_dev_msg(KERN_WARNING, h, device, + if (sdev) { + scsi_remove_device(sdev); + scsi_device_put(sdev); + } else { + /* + * We don't expect to get here. Future commands + * to this device will get a selection timeout as + * if the device were gone. + */ + hpsa_show_dev_msg(KERN_WARNING, h, device, "didn't find device for removal."); - } + } + } else /* HBA */ + hpsa_remove_sas_device(device); } static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno, @@ -1915,11 +1934,24 @@ static int hpsa_slave_alloc(struct scsi_device *sdev) h = sdev_to_hba(sdev); spin_lock_irqsave(&h->devlock, flags); - sd = lookup_hpsa_scsi_dev(h, sdev_channel(sdev), - sdev_id(sdev), sdev->lun); - if (likely(sd)) { + if (sdev_channel(sdev) == HPSA_PHYSICAL_DEVICE_BUS) { + struct scsi_target *starget; + struct sas_rphy *rphy; + + starget = scsi_target(sdev); + rphy = target_to_rphy(starget); + sd = hpsa_find_device_by_sas_rphy(h, rphy); + if (sd) { + sd->target = sdev_id(sdev); + sd->lun = sdev->lun; + } + } else + sd = lookup_hpsa_scsi_dev(h, sdev_channel(sdev), + sdev_id(sdev), sdev->lun); + + if (sd && sd->expose_device) { atomic_set(&sd->ioaccel_cmds_out, 0); - sdev->hostdata = sd->expose_device ? sd : NULL; + sdev->hostdata = sd; } else sdev->hostdata = NULL; spin_unlock_irqrestore(&h->devlock, flags); @@ -3069,6 +3101,38 @@ out: return rc; } +static int hpsa_bmic_sense_subsystem_information(struct ctlr_info *h, + unsigned char scsi3addr[], u16 bmic_device_index, + struct bmic_sense_subsystem_info *buf, size_t bufsize) +{ + int rc = IO_OK; + struct CommandList *c; + struct ErrorInfo *ei; + + c = cmd_alloc(h); + + rc = fill_cmd(c, BMIC_SENSE_SUBSYSTEM_INFORMATION, h, buf, bufsize, + 0, RAID_CTLR_LUNID, TYPE_CMD); + if (rc) + goto out; + + c->Request.CDB[2] = bmic_device_index & 0xff; + c->Request.CDB[9] = (bmic_device_index >> 8) & 0xff; + + rc = hpsa_scsi_do_simple_cmd_with_retry(h, c, + PCI_DMA_FROMDEVICE, NO_TIMEOUT); + if (rc) + goto out; + ei = c->err_info; + if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) { + hpsa_scsi_interpret_error(h, c); + rc = -1; + } +out: + cmd_free(h, c); + return rc; +} + static int hpsa_bmic_id_controller(struct ctlr_info *h, struct bmic_identify_controller *buf, size_t bufsize) { @@ -3097,7 +3161,6 @@ out: return rc; } - static int hpsa_bmic_id_physical_device(struct ctlr_info *h, unsigned char scsi3addr[], u16 bmic_device_index, struct bmic_identify_physical_device *buf, size_t bufsize) @@ -3124,9 +3187,64 @@ static int hpsa_bmic_id_physical_device(struct ctlr_info *h, } out: cmd_free(h, c); + return rc; } +static u64 hpsa_get_sas_address_from_report_physical(struct ctlr_info *h, + unsigned char *scsi3addr) +{ + struct ReportExtendedLUNdata *physdev; + u32 nphysicals; + u64 sa = 0; + int i; + + physdev = kzalloc(sizeof(*physdev), GFP_KERNEL); + if (!physdev) + return 0; + + if (hpsa_scsi_do_report_phys_luns(h, physdev, sizeof(*physdev))) { + dev_err(&h->pdev->dev, "report physical LUNs failed.\n"); + kfree(physdev); + return 0; + } + nphysicals = get_unaligned_be32(physdev->LUNListLength) / 24; + + for (i = 0; i < nphysicals; i++) + if (!memcmp(&physdev->LUN[i].lunid[0], scsi3addr, 8)) + sa = get_unaligned_be64(&physdev->LUN[i].wwid[0]); + + kfree(physdev); + + return sa; +} + +static void hpsa_get_sas_address(struct ctlr_info *h, unsigned char *scsi3addr, + struct hpsa_scsi_dev_t *dev) +{ + int rc; + u64 sa = 0; + + if (is_hba_lunid(scsi3addr)) { + struct bmic_sense_subsystem_info *ssi; + + ssi = kzalloc(sizeof(*ssi), GFP_KERNEL); + + rc = hpsa_bmic_sense_subsystem_information(h, + scsi3addr, 0, ssi, sizeof(*ssi)); + if (rc == 0) { + sa = get_unaligned_be64(ssi->primary_world_wide_id); + h->sas_address = sa; + } + + kfree(ssi); + } else + sa = hpsa_get_sas_address_from_report_physical(h, scsi3addr); + + dev->sas_address = sa; +} + +/* Get a device id from inquiry page 0x83 */ static int hpsa_vpd_page_supported(struct ctlr_info *h, unsigned char scsi3addr[], u8 page) { @@ -3961,6 +4079,13 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) else this_device->expose_device = 1; + + /* + * Get the SAS address for physical devices that are exposed. + */ + if (this_device->physical_device && this_device->expose_device) + hpsa_get_sas_address(h, lunaddrbytes, this_device); + switch (this_device->devtype) { case TYPE_ROM: /* We don't *really* support actual CD-ROM devices, @@ -4006,6 +4131,10 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno) if (ncurrent >= HPSA_MAX_DEVICES) break; } + + if (h->sas_host == NULL) + hpsa_add_sas_host(h); + adjust_hpsa_scsi_table(h, hostno, currentsd, ncurrent); out: kfree(tmpdevice); @@ -5137,6 +5266,7 @@ static int hpsa_scsi_host_alloc(struct ctlr_info *h) sh->can_queue = h->nr_cmds - HPSA_NRESERVED_CMDS; sh->cmd_per_lun = sh->can_queue; sh->sg_tablesize = h->maxsgentries; + sh->transportt = hpsa_sas_transport_template; sh->hostdata[0] = (unsigned long) h; sh->irq = h->intr[h->intr_mode]; sh->unique_id = sh->irq; @@ -6485,6 +6615,16 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, c->Request.CDB[7] = (size >> 16) & 0xFF; c->Request.CDB[8] = (size >> 8) & 0XFF; break; + case BMIC_SENSE_SUBSYSTEM_INFORMATION: + c->Request.CDBLen = 10; + c->Request.type_attr_dir = + TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ); + c->Request.Timeout = 0; + c->Request.CDB[0] = BMIC_READ; + c->Request.CDB[6] = BMIC_SENSE_SUBSYSTEM_INFORMATION; + c->Request.CDB[7] = (size >> 16) & 0xFF; + c->Request.CDB[8] = (size >> 8) & 0XFF; + break; case BMIC_IDENTIFY_CONTROLLER: c->Request.CDBLen = 10; c->Request.type_attr_dir = @@ -6501,7 +6641,6 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h, c->Request.CDB[8] = (size >> 8) & 0XFF; c->Request.CDB[9] = 0; break; - default: dev_warn(&h->pdev->dev, "unknown command 0x%c\n", cmd); BUG(); @@ -8618,6 +8757,9 @@ static void hpsa_remove_one(struct pci_dev *pdev) free_percpu(h->lockup_detected); /* init_one 2 */ h->lockup_detected = NULL; /* init_one 2 */ /* (void) pci_disable_pcie_error_reporting(pdev); */ /* init_one 1 */ + + hpsa_delete_sas_host(h); + kfree(h); /* init_one 1 */ } @@ -9080,18 +9222,369 @@ static void hpsa_drain_accel_commands(struct ctlr_info *h) } while (1); } +static struct hpsa_sas_phy *hpsa_alloc_sas_phy( + struct hpsa_sas_port *hpsa_sas_port) +{ + struct hpsa_sas_phy *hpsa_sas_phy; + struct sas_phy *phy; + + hpsa_sas_phy = kzalloc(sizeof(*hpsa_sas_phy), GFP_KERNEL); + if (!hpsa_sas_phy) + return NULL; + + phy = sas_phy_alloc(hpsa_sas_port->parent_node->parent_dev, + hpsa_sas_port->next_phy_index); + if (!phy) { + kfree(hpsa_sas_phy); + return NULL; + } + + hpsa_sas_port->next_phy_index++; + hpsa_sas_phy->phy = phy; + hpsa_sas_phy->parent_port = hpsa_sas_port; + + return hpsa_sas_phy; +} + +static void hpsa_free_sas_phy(struct hpsa_sas_phy *hpsa_sas_phy) +{ + struct sas_phy *phy = hpsa_sas_phy->phy; + + sas_port_delete_phy(hpsa_sas_phy->parent_port->port, phy); + sas_phy_free(phy); + if (hpsa_sas_phy->added_to_port) + list_del(&hpsa_sas_phy->phy_list_entry); + kfree(hpsa_sas_phy); +} + +static int hpsa_sas_port_add_phy(struct hpsa_sas_phy *hpsa_sas_phy) +{ + int rc; + struct hpsa_sas_port *hpsa_sas_port; + struct sas_phy *phy; + struct sas_identify *identify; + + hpsa_sas_port = hpsa_sas_phy->parent_port; + phy = hpsa_sas_phy->phy; + + identify = &phy->identify; + memset(identify, 0, sizeof(*identify)); + identify->sas_address = hpsa_sas_port->sas_address; + identify->device_type = SAS_END_DEVICE; + identify->initiator_port_protocols = SAS_PROTOCOL_STP; + identify->target_port_protocols = SAS_PROTOCOL_STP; + phy->minimum_linkrate_hw = SAS_LINK_RATE_UNKNOWN; + phy->maximum_linkrate_hw = SAS_LINK_RATE_UNKNOWN; + phy->minimum_linkrate = SAS_LINK_RATE_UNKNOWN; + phy->maximum_linkrate = SAS_LINK_RATE_UNKNOWN; + phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN; + + rc = sas_phy_add(hpsa_sas_phy->phy); + if (rc) + return rc; + + sas_port_add_phy(hpsa_sas_port->port, hpsa_sas_phy->phy); + list_add_tail(&hpsa_sas_phy->phy_list_entry, + &hpsa_sas_port->phy_list_head); + hpsa_sas_phy->added_to_port = true; + + return 0; +} + +static int + hpsa_sas_port_add_rphy(struct hpsa_sas_port *hpsa_sas_port, + struct sas_rphy *rphy) +{ + struct sas_identify *identify; + + identify = &rphy->identify; + identify->sas_address = hpsa_sas_port->sas_address; + identify->initiator_port_protocols = SAS_PROTOCOL_STP; + identify->target_port_protocols = SAS_PROTOCOL_STP; + + return sas_rphy_add(rphy); +} + +static struct hpsa_sas_port + *hpsa_alloc_sas_port(struct hpsa_sas_node *hpsa_sas_node, + u64 sas_address) +{ + int rc; + struct hpsa_sas_port *hpsa_sas_port; + struct sas_port *port; + + hpsa_sas_port = kzalloc(sizeof(*hpsa_sas_port), GFP_KERNEL); + if (!hpsa_sas_port) + return NULL; + + INIT_LIST_HEAD(&hpsa_sas_port->phy_list_head); + hpsa_sas_port->parent_node = hpsa_sas_node; + + port = sas_port_alloc_num(hpsa_sas_node->parent_dev); + if (!port) + goto free_hpsa_port; + + rc = sas_port_add(port); + if (rc) + goto free_sas_port; + + hpsa_sas_port->port = port; + hpsa_sas_port->sas_address = sas_address; + list_add_tail(&hpsa_sas_port->port_list_entry, + &hpsa_sas_node->port_list_head); + + return hpsa_sas_port; + +free_sas_port: + sas_port_free(port); +free_hpsa_port: + kfree(hpsa_sas_port); + + return NULL; +} + +static void hpsa_free_sas_port(struct hpsa_sas_port *hpsa_sas_port) +{ + struct hpsa_sas_phy *hpsa_sas_phy; + struct hpsa_sas_phy *next; + + list_for_each_entry_safe(hpsa_sas_phy, next, + &hpsa_sas_port->phy_list_head, phy_list_entry) + hpsa_free_sas_phy(hpsa_sas_phy); + + sas_port_delete(hpsa_sas_port->port); + list_del(&hpsa_sas_port->port_list_entry); + kfree(hpsa_sas_port); +} + +static struct hpsa_sas_node *hpsa_alloc_sas_node(struct device *parent_dev) +{ + struct hpsa_sas_node *hpsa_sas_node; + + hpsa_sas_node = kzalloc(sizeof(*hpsa_sas_node), GFP_KERNEL); + if (hpsa_sas_node) { + hpsa_sas_node->parent_dev = parent_dev; + INIT_LIST_HEAD(&hpsa_sas_node->port_list_head); + } + + return hpsa_sas_node; +} + +static void hpsa_free_sas_node(struct hpsa_sas_node *hpsa_sas_node) +{ + struct hpsa_sas_port *hpsa_sas_port; + struct hpsa_sas_port *next; + + if (!hpsa_sas_node) + return; + + list_for_each_entry_safe(hpsa_sas_port, next, + &hpsa_sas_node->port_list_head, port_list_entry) + hpsa_free_sas_port(hpsa_sas_port); + + kfree(hpsa_sas_node); +} + +static struct hpsa_scsi_dev_t + *hpsa_find_device_by_sas_rphy(struct ctlr_info *h, + struct sas_rphy *rphy) +{ + int i; + struct hpsa_scsi_dev_t *device; + + for (i = 0; i < h->ndevices; i++) { + device = h->dev[i]; + if (!device->sas_port) + continue; + if (device->sas_port->rphy == rphy) + return device; + } + + return NULL; +} + +static int hpsa_add_sas_host(struct ctlr_info *h) +{ + int rc; + struct device *parent_dev; + struct hpsa_sas_node *hpsa_sas_node; + struct hpsa_sas_port *hpsa_sas_port; + struct hpsa_sas_phy *hpsa_sas_phy; + + parent_dev = &h->scsi_host->shost_gendev; + + hpsa_sas_node = hpsa_alloc_sas_node(parent_dev); + if (!hpsa_sas_node) + return -ENOMEM; + + hpsa_sas_port = hpsa_alloc_sas_port(hpsa_sas_node, h->sas_address); + if (!hpsa_sas_port) { + rc = -ENODEV; + goto free_sas_node; + } + + hpsa_sas_phy = hpsa_alloc_sas_phy(hpsa_sas_port); + if (!hpsa_sas_phy) { + rc = -ENODEV; + goto free_sas_port; + } + + rc = hpsa_sas_port_add_phy(hpsa_sas_phy); + if (rc) + goto free_sas_phy; + + h->sas_host = hpsa_sas_node; + + return 0; + +free_sas_phy: + hpsa_free_sas_phy(hpsa_sas_phy); +free_sas_port: + hpsa_free_sas_port(hpsa_sas_port); +free_sas_node: + hpsa_free_sas_node(hpsa_sas_node); + + return rc; +} + +static void hpsa_delete_sas_host(struct ctlr_info *h) +{ + hpsa_free_sas_node(h->sas_host); +} + +static int hpsa_add_sas_device(struct hpsa_sas_node *hpsa_sas_node, + struct hpsa_scsi_dev_t *device) +{ + int rc; + struct hpsa_sas_port *hpsa_sas_port; + struct sas_rphy *rphy; + + hpsa_sas_port = hpsa_alloc_sas_port(hpsa_sas_node, device->sas_address); + if (!hpsa_sas_port) + return -ENOMEM; + + rphy = sas_end_device_alloc(hpsa_sas_port->port); + if (!rphy) { + rc = -ENODEV; + goto free_sas_port; + } + + hpsa_sas_port->rphy = rphy; + device->sas_port = hpsa_sas_port; + + rc = hpsa_sas_port_add_rphy(hpsa_sas_port, rphy); + if (rc) + goto free_sas_port; + + return 0; + +free_sas_port: + hpsa_free_sas_port(hpsa_sas_port); + device->sas_port = NULL; + + return rc; +} + +static void hpsa_remove_sas_device(struct hpsa_scsi_dev_t *device) +{ + if (device->sas_port) { + hpsa_free_sas_port(device->sas_port); + device->sas_port = NULL; + } +} + +static int +hpsa_sas_get_linkerrors(struct sas_phy *phy) +{ + return 0; +} + +static int +hpsa_sas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier) +{ + return 0; +} + +static int +hpsa_sas_get_bay_identifier(struct sas_rphy *rphy) +{ + return -ENXIO; +} + +static int +hpsa_sas_phy_reset(struct sas_phy *phy, int hard_reset) +{ + return 0; +} + +static int +hpsa_sas_phy_enable(struct sas_phy *phy, int enable) +{ + return 0; +} + +static int +hpsa_sas_phy_setup(struct sas_phy *phy) +{ + return 0; +} + +static void +hpsa_sas_phy_release(struct sas_phy *phy) +{ +} + +static int +hpsa_sas_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates) +{ + return -EINVAL; +} + +/* SMP = Serial Management Protocol */ +static int +hpsa_sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy, +struct request *req) +{ + return -EINVAL; +} + +static struct sas_function_template hpsa_sas_transport_functions = { + .get_linkerrors = hpsa_sas_get_linkerrors, + .get_enclosure_identifier = hpsa_sas_get_enclosure_identifier, + .get_bay_identifier = hpsa_sas_get_bay_identifier, + .phy_reset = hpsa_sas_phy_reset, + .phy_enable = hpsa_sas_phy_enable, + .phy_setup = hpsa_sas_phy_setup, + .phy_release = hpsa_sas_phy_release, + .set_phy_speed = hpsa_sas_phy_speed, + .smp_handler = hpsa_sas_smp_handler, +}; + /* * This is it. Register the PCI driver information for the cards we control * the OS will call our registered routines when it finds one of our cards. */ static int __init hpsa_init(void) { - return pci_register_driver(&hpsa_pci_driver); + int rc; + + hpsa_sas_transport_template = + sas_attach_transport(&hpsa_sas_transport_functions); + if (!hpsa_sas_transport_template) + return -ENODEV; + + rc = pci_register_driver(&hpsa_pci_driver); + + if (rc) + sas_release_transport(hpsa_sas_transport_template); + + return rc; } static void __exit hpsa_cleanup(void) { pci_unregister_driver(&hpsa_pci_driver); + sas_release_transport(hpsa_sas_transport_template); } static void __attribute__((unused)) verify_offsets(void) diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h index 6c82d3c..7847405 100644 --- a/drivers/scsi/hpsa.h +++ b/drivers/scsi/hpsa.h @@ -33,6 +33,29 @@ struct access_method { unsigned long (*command_completed)(struct ctlr_info *h, u8 q); }; +/* for SAS hosts and SAS expanders */ +struct hpsa_sas_node { + struct device *parent_dev; + struct list_head port_list_head; +}; + +struct hpsa_sas_port { + struct list_head port_list_entry; + u64 sas_address; + struct sas_port *port; + int next_phy_index; + struct list_head phy_list_head; + struct hpsa_sas_node *parent_node; + struct sas_rphy *rphy; +}; + +struct hpsa_sas_phy { + struct list_head phy_list_entry; + struct sas_phy *phy; + struct hpsa_sas_port *parent_port; + bool added_to_port; +}; + struct hpsa_scsi_dev_t { unsigned int devtype; int bus, target, lun; /* as presented to the OS */ @@ -41,6 +64,7 @@ struct hpsa_scsi_dev_t { u8 expose_device; #define RAID_CTLR_LUNID "\0\0\0\0\0\0\0\0" unsigned char device_id[16]; /* from inquiry pg. 0x83 */ + u64 sas_address; unsigned char vendor[8]; /* bytes 8-15 of inquiry data */ unsigned char model[16]; /* bytes 16-31 of inquiry data */ unsigned char raid_level; /* from inquiry page 0xC1 */ @@ -77,6 +101,7 @@ struct hpsa_scsi_dev_t { struct hpsa_scsi_dev_t *phys_disk[RAID_MAP_MAX_ENTRIES]; int nphysical_disks; int supports_aborts; + struct hpsa_sas_port *sas_port; int external; /* 1-from external array 0-not <0-unknown */ }; @@ -134,6 +159,7 @@ struct ctlr_info { char *product_name; struct pci_dev *pdev; u32 board_id; + u64 sas_address; void __iomem *vaddr; unsigned long paddr; int nr_cmds; /* Number of commands allowed on this controller */ @@ -272,6 +298,7 @@ struct ctlr_info { wait_queue_head_t event_sync_wait_queue; struct mutex reset_mutex; u8 reset_in_progress; + struct hpsa_sas_node *sas_host; }; struct offline_device_entry { diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h index 4910344..d92ef0d 100644 --- a/drivers/scsi/hpsa_cmd.h +++ b/drivers/scsi/hpsa_cmd.h @@ -290,6 +290,7 @@ struct SenseSubsystem_info { #define BMIC_SET_DIAG_OPTIONS 0xF4 #define BMIC_SENSE_DIAG_OPTIONS 0xF5 #define HPSA_DIAG_OPTS_DISABLE_RLD_CACHING 0x40000000 +#define BMIC_SENSE_SUBSYSTEM_INFORMATION 0x66 /* Command List Structure */ union SCSI3Addr { @@ -828,5 +829,18 @@ struct bmic_identify_physical_device { u8 padding[112]; }; +struct bmic_sense_subsystem_info { + u8 primary_slot_number; + u8 reserved[3]; + u8 chasis_serial_number[32]; + u8 primary_world_wide_id[8]; + u8 primary_array_serial_number[32]; /* NULL terminated */ + u8 primary_cache_serial_number[32]; /* NULL terminated */ + u8 reserved_2[8]; + u8 secondary_array_serial_number[32]; + u8 secondary_cache_serial_number[32]; + u8 pad[332]; +}; + #pragma pack() #endif /* HPSA_CMD_H */