Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Serial Attached SCSI (SAS) Expander discovery and configuration
0004  *
0005  * Copyright (C) 2007 James E.J. Bottomley
0006  *      <James.Bottomley@HansenPartnership.com>
0007  */
0008 #include <linux/scatterlist.h>
0009 #include <linux/blkdev.h>
0010 #include <linux/slab.h>
0011 #include <linux/export.h>
0012 
0013 #include "sas_internal.h"
0014 
0015 #include <scsi/scsi_transport.h>
0016 #include <scsi/scsi_transport_sas.h>
0017 #include "scsi_sas_internal.h"
0018 
0019 static void sas_host_smp_discover(struct sas_ha_struct *sas_ha, u8 *resp_data,
0020                   u8 phy_id)
0021 {
0022     struct sas_phy *phy;
0023     struct sas_rphy *rphy;
0024 
0025     if (phy_id >= sas_ha->num_phys) {
0026         resp_data[2] = SMP_RESP_NO_PHY;
0027         return;
0028     }
0029     resp_data[2] = SMP_RESP_FUNC_ACC;
0030 
0031     phy = sas_ha->sas_phy[phy_id]->phy;
0032     resp_data[9] = phy_id;
0033     resp_data[13] = phy->negotiated_linkrate;
0034     memcpy(resp_data + 16, sas_ha->sas_addr, SAS_ADDR_SIZE);
0035     memcpy(resp_data + 24, sas_ha->sas_phy[phy_id]->attached_sas_addr,
0036            SAS_ADDR_SIZE);
0037     resp_data[40] = (phy->minimum_linkrate << 4) |
0038         phy->minimum_linkrate_hw;
0039     resp_data[41] = (phy->maximum_linkrate << 4) |
0040         phy->maximum_linkrate_hw;
0041 
0042     if (!sas_ha->sas_phy[phy_id]->port ||
0043         !sas_ha->sas_phy[phy_id]->port->port_dev)
0044         return;
0045 
0046     rphy = sas_ha->sas_phy[phy_id]->port->port_dev->rphy;
0047     resp_data[12] = rphy->identify.device_type << 4;
0048     resp_data[14] = rphy->identify.initiator_port_protocols;
0049     resp_data[15] = rphy->identify.target_port_protocols;
0050 }
0051 
0052 /**
0053  * to_sas_gpio_gp_bit - given the gpio frame data find the byte/bit position of 'od'
0054  * @od: od bit to find
0055  * @data: incoming bitstream (from frame)
0056  * @index: requested data register index (from frame)
0057  * @count: total number of registers in the bitstream (from frame)
0058  * @bit: bit position of 'od' in the returned byte
0059  *
0060  * returns NULL if 'od' is not in 'data'
0061  *
0062  * From SFF-8485 v0.7:
0063  * "In GPIO_TX[1], bit 0 of byte 3 contains the first bit (i.e., OD0.0)
0064  *  and bit 7 of byte 0 contains the 32nd bit (i.e., OD10.1).
0065  *
0066  *  In GPIO_TX[2], bit 0 of byte 3 contains the 33rd bit (i.e., OD10.2)
0067  *  and bit 7 of byte 0 contains the 64th bit (i.e., OD21.0)."
0068  *
0069  * The general-purpose (raw-bitstream) RX registers have the same layout
0070  * although 'od' is renamed 'id' for 'input data'.
0071  *
0072  * SFF-8489 defines the behavior of the LEDs in response to the 'od' values.
0073  */
0074 static u8 *to_sas_gpio_gp_bit(unsigned int od, u8 *data, u8 index, u8 count, u8 *bit)
0075 {
0076     unsigned int reg;
0077     u8 byte;
0078 
0079     /* gp registers start at index 1 */
0080     if (index == 0)
0081         return NULL;
0082 
0083     index--; /* make index 0-based */
0084     if (od < index * 32)
0085         return NULL;
0086 
0087     od -= index * 32;
0088     reg = od >> 5;
0089 
0090     if (reg >= count)
0091         return NULL;
0092 
0093     od &= (1 << 5) - 1;
0094     byte = 3 - (od >> 3);
0095     *bit = od & ((1 << 3) - 1);
0096 
0097     return &data[reg * 4 + byte];
0098 }
0099 
0100 int try_test_sas_gpio_gp_bit(unsigned int od, u8 *data, u8 index, u8 count)
0101 {
0102     u8 *byte;
0103     u8 bit;
0104 
0105     byte = to_sas_gpio_gp_bit(od, data, index, count, &bit);
0106     if (!byte)
0107         return -1;
0108 
0109     return (*byte >> bit) & 1;
0110 }
0111 EXPORT_SYMBOL(try_test_sas_gpio_gp_bit);
0112 
0113 static int sas_host_smp_write_gpio(struct sas_ha_struct *sas_ha, u8 *resp_data,
0114                    u8 reg_type, u8 reg_index, u8 reg_count,
0115                    u8 *req_data)
0116 {
0117     struct sas_internal *i = to_sas_internal(sas_ha->core.shost->transportt);
0118     int written;
0119 
0120     if (i->dft->lldd_write_gpio == NULL) {
0121         resp_data[2] = SMP_RESP_FUNC_UNK;
0122         return 0;
0123     }
0124 
0125     written = i->dft->lldd_write_gpio(sas_ha, reg_type, reg_index,
0126                       reg_count, req_data);
0127 
0128     if (written < 0) {
0129         resp_data[2] = SMP_RESP_FUNC_FAILED;
0130         written = 0;
0131     } else
0132         resp_data[2] = SMP_RESP_FUNC_ACC;
0133 
0134     return written;
0135 }
0136 
0137 static void sas_report_phy_sata(struct sas_ha_struct *sas_ha, u8 *resp_data,
0138                 u8 phy_id)
0139 {
0140     struct sas_rphy *rphy;
0141     struct dev_to_host_fis *fis;
0142     int i;
0143 
0144     if (phy_id >= sas_ha->num_phys) {
0145         resp_data[2] = SMP_RESP_NO_PHY;
0146         return;
0147     }
0148 
0149     resp_data[2] = SMP_RESP_PHY_NO_SATA;
0150 
0151     if (!sas_ha->sas_phy[phy_id]->port)
0152         return;
0153 
0154     rphy = sas_ha->sas_phy[phy_id]->port->port_dev->rphy;
0155     fis = (struct dev_to_host_fis *)
0156         sas_ha->sas_phy[phy_id]->port->port_dev->frame_rcvd;
0157     if (rphy->identify.target_port_protocols != SAS_PROTOCOL_SATA)
0158         return;
0159 
0160     resp_data[2] = SMP_RESP_FUNC_ACC;
0161     resp_data[9] = phy_id;
0162     memcpy(resp_data + 16, sas_ha->sas_phy[phy_id]->attached_sas_addr,
0163            SAS_ADDR_SIZE);
0164 
0165     /* check to see if we have a valid d2h fis */
0166     if (fis->fis_type != 0x34)
0167         return;
0168 
0169     /* the d2h fis is required by the standard to be in LE format */
0170     for (i = 0; i < 20; i += 4) {
0171         u8 *dst = resp_data + 24 + i, *src =
0172             &sas_ha->sas_phy[phy_id]->port->port_dev->frame_rcvd[i];
0173         dst[0] = src[3];
0174         dst[1] = src[2];
0175         dst[2] = src[1];
0176         dst[3] = src[0];
0177     }
0178 }
0179 
0180 static void sas_phy_control(struct sas_ha_struct *sas_ha, u8 phy_id,
0181                 u8 phy_op, enum sas_linkrate min,
0182                 enum sas_linkrate max, u8 *resp_data)
0183 {
0184     struct sas_internal *i =
0185         to_sas_internal(sas_ha->core.shost->transportt);
0186     struct sas_phy_linkrates rates;
0187     struct asd_sas_phy *asd_phy;
0188 
0189     if (phy_id >= sas_ha->num_phys) {
0190         resp_data[2] = SMP_RESP_NO_PHY;
0191         return;
0192     }
0193 
0194     asd_phy = sas_ha->sas_phy[phy_id];
0195     switch (phy_op) {
0196     case PHY_FUNC_NOP:
0197     case PHY_FUNC_LINK_RESET:
0198     case PHY_FUNC_HARD_RESET:
0199     case PHY_FUNC_DISABLE:
0200     case PHY_FUNC_CLEAR_ERROR_LOG:
0201     case PHY_FUNC_CLEAR_AFFIL:
0202     case PHY_FUNC_TX_SATA_PS_SIGNAL:
0203         break;
0204 
0205     default:
0206         resp_data[2] = SMP_RESP_PHY_UNK_OP;
0207         return;
0208     }
0209 
0210     rates.minimum_linkrate = min;
0211     rates.maximum_linkrate = max;
0212 
0213     /* filter reset requests through libata eh */
0214     if (phy_op == PHY_FUNC_LINK_RESET && sas_try_ata_reset(asd_phy) == 0) {
0215         resp_data[2] = SMP_RESP_FUNC_ACC;
0216         return;
0217     }
0218 
0219     if (i->dft->lldd_control_phy(asd_phy, phy_op, &rates))
0220         resp_data[2] = SMP_RESP_FUNC_FAILED;
0221     else
0222         resp_data[2] = SMP_RESP_FUNC_ACC;
0223 }
0224 
0225 void sas_smp_host_handler(struct bsg_job *job, struct Scsi_Host *shost)
0226 {
0227     struct sas_ha_struct *sas_ha = SHOST_TO_SAS_HA(shost);
0228     u8 *req_data, *resp_data;
0229     unsigned int reslen = 0;
0230     int error = -EINVAL;
0231 
0232     /* eight is the minimum size for request and response frames */
0233     if (job->request_payload.payload_len < 8 ||
0234         job->reply_payload.payload_len < 8)
0235         goto out;
0236 
0237     error = -ENOMEM;
0238     req_data = kzalloc(job->request_payload.payload_len, GFP_KERNEL);
0239     if (!req_data)
0240         goto out;
0241     sg_copy_to_buffer(job->request_payload.sg_list,
0242               job->request_payload.sg_cnt, req_data,
0243               job->request_payload.payload_len);
0244 
0245     /* make sure frame can always be built ... we copy
0246      * back only the requested length */
0247     resp_data = kzalloc(max(job->reply_payload.payload_len, 128U),
0248             GFP_KERNEL);
0249     if (!resp_data)
0250         goto out_free_req;
0251 
0252     error = -EINVAL;
0253     if (req_data[0] != SMP_REQUEST)
0254         goto out_free_resp;
0255 
0256     /* set up default don't know response */
0257     resp_data[0] = SMP_RESPONSE;
0258     resp_data[1] = req_data[1];
0259     resp_data[2] = SMP_RESP_FUNC_UNK;
0260 
0261     switch (req_data[1]) {
0262     case SMP_REPORT_GENERAL:
0263         resp_data[2] = SMP_RESP_FUNC_ACC;
0264         resp_data[9] = sas_ha->num_phys;
0265         reslen = 32;
0266         break;
0267 
0268     case SMP_REPORT_MANUF_INFO:
0269         resp_data[2] = SMP_RESP_FUNC_ACC;
0270         memcpy(resp_data + 12, shost->hostt->name,
0271                SAS_EXPANDER_VENDOR_ID_LEN);
0272         memcpy(resp_data + 20, "libsas virt phy",
0273                SAS_EXPANDER_PRODUCT_ID_LEN);
0274         reslen = 64;
0275         break;
0276 
0277     case SMP_READ_GPIO_REG:
0278         /* FIXME: need GPIO support in the transport class */
0279         break;
0280 
0281     case SMP_DISCOVER:
0282         if (job->request_payload.payload_len < 16)
0283             goto out_free_resp;
0284         sas_host_smp_discover(sas_ha, resp_data, req_data[9]);
0285         reslen = 56;
0286         break;
0287 
0288     case SMP_REPORT_PHY_ERR_LOG:
0289         /* FIXME: could implement this with additional
0290          * libsas callbacks providing the HW supports it */
0291         break;
0292 
0293     case SMP_REPORT_PHY_SATA:
0294         if (job->request_payload.payload_len < 16)
0295             goto out_free_resp;
0296         sas_report_phy_sata(sas_ha, resp_data, req_data[9]);
0297         reslen = 60;
0298         break;
0299 
0300     case SMP_REPORT_ROUTE_INFO:
0301         /* Can't implement; hosts have no routes */
0302         break;
0303 
0304     case SMP_WRITE_GPIO_REG: {
0305         /* SFF-8485 v0.7 */
0306         const int base_frame_size = 11;
0307         int to_write = req_data[4];
0308 
0309         if (job->request_payload.payload_len <
0310                 base_frame_size + to_write * 4) {
0311             resp_data[2] = SMP_RESP_INV_FRM_LEN;
0312             break;
0313         }
0314 
0315         to_write = sas_host_smp_write_gpio(sas_ha, resp_data, req_data[2],
0316                            req_data[3], to_write, &req_data[8]);
0317         reslen = 8;
0318         break;
0319     }
0320 
0321     case SMP_CONF_ROUTE_INFO:
0322         /* Can't implement; hosts have no routes */
0323         break;
0324 
0325     case SMP_PHY_CONTROL:
0326         if (job->request_payload.payload_len < 44)
0327             goto out_free_resp;
0328         sas_phy_control(sas_ha, req_data[9], req_data[10],
0329                 req_data[32] >> 4, req_data[33] >> 4,
0330                 resp_data);
0331         reslen = 8;
0332         break;
0333 
0334     case SMP_PHY_TEST_FUNCTION:
0335         /* FIXME: should this be implemented? */
0336         break;
0337 
0338     default:
0339         /* probably a 2.0 function */
0340         break;
0341     }
0342 
0343     sg_copy_from_buffer(job->reply_payload.sg_list,
0344                 job->reply_payload.sg_cnt, resp_data,
0345                 job->reply_payload.payload_len);
0346 
0347     error = 0;
0348 out_free_resp:
0349     kfree(resp_data);
0350 out_free_req:
0351     kfree(req_data);
0352 out:
0353     bsg_job_done(job, error, reslen);
0354 }