0001
0002
0003
0004
0005
0006
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
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
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
0080 if (index == 0)
0081 return NULL;
0082
0083 index--;
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
0166 if (fis->fis_type != 0x34)
0167 return;
0168
0169
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
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
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
0246
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
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
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
0290
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
0302 break;
0303
0304 case SMP_WRITE_GPIO_REG: {
0305
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
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
0336 break;
0337
0338 default:
0339
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 }