aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/message/fusion/mptsas.c126
1 files changed, 126 insertions, 0 deletions
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c
index 29add83da588..b9c69bff218c 100644
--- a/drivers/message/fusion/mptsas.c
+++ b/drivers/message/fusion/mptsas.c
@@ -1312,11 +1312,137 @@ mptsas_get_bay_identifier(struct sas_rphy *rphy)
1312 return rc; 1312 return rc;
1313} 1313}
1314 1314
1315static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
1316 struct request *req)
1317{
1318 MPT_ADAPTER *ioc = ((MPT_SCSI_HOST *) shost->hostdata)->ioc;
1319 MPT_FRAME_HDR *mf;
1320 SmpPassthroughRequest_t *smpreq;
1321 struct request *rsp = req->next_rq;
1322 int ret;
1323 int flagsLength;
1324 unsigned long timeleft;
1325 char *psge;
1326 dma_addr_t dma_addr_in = 0;
1327 dma_addr_t dma_addr_out = 0;
1328 u64 sas_address = 0;
1329
1330 if (!rsp) {
1331 printk(KERN_ERR "%s: the smp response space is missing\n",
1332 __FUNCTION__);
1333 return -EINVAL;
1334 }
1335
1336 /* do we need to support multiple segments? */
1337 if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
1338 printk(KERN_ERR "%s: multiple segments req %u %u, rsp %u %u\n",
1339 __FUNCTION__, req->bio->bi_vcnt, req->data_len,
1340 rsp->bio->bi_vcnt, rsp->data_len);
1341 return -EINVAL;
1342 }
1343
1344 ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
1345 if (ret)
1346 goto out;
1347
1348 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
1349 if (!mf) {
1350 ret = -ENOMEM;
1351 goto out_unlock;
1352 }
1353
1354 smpreq = (SmpPassthroughRequest_t *)mf;
1355 memset(smpreq, 0, sizeof(*smpreq));
1356
1357 smpreq->RequestDataLength = cpu_to_le16(req->data_len - 4);
1358 smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
1359
1360 if (rphy)
1361 sas_address = rphy->identify.sas_address;
1362 else {
1363 struct mptsas_portinfo *port_info;
1364
1365 mutex_lock(&ioc->sas_topology_mutex);
1366 port_info = mptsas_find_portinfo_by_handle(ioc, ioc->handle);
1367 if (port_info && port_info->phy_info)
1368 sas_address =
1369 port_info->phy_info[0].phy->identify.sas_address;
1370 mutex_unlock(&ioc->sas_topology_mutex);
1371 }
1372
1373 *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
1374
1375 psge = (char *)
1376 (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
1377
1378 /* request */
1379 flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
1380 MPI_SGE_FLAGS_END_OF_BUFFER |
1381 MPI_SGE_FLAGS_DIRECTION |
1382 mpt_addr_size()) << MPI_SGE_FLAGS_SHIFT;
1383 flagsLength |= (req->data_len - 4);
1384
1385 dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio),
1386 req->data_len, PCI_DMA_BIDIRECTIONAL);
1387 if (!dma_addr_out)
1388 goto put_mf;
1389 mpt_add_sge(psge, flagsLength, dma_addr_out);
1390 psge += (sizeof(u32) + sizeof(dma_addr_t));
1391
1392 /* response */
1393 flagsLength = MPT_SGE_FLAGS_SSIMPLE_READ;
1394 flagsLength |= rsp->data_len + 4;
1395 dma_addr_in = pci_map_single(ioc->pcidev, bio_data(rsp->bio),
1396 rsp->data_len, PCI_DMA_BIDIRECTIONAL);
1397 if (!dma_addr_in)
1398 goto unmap;
1399 mpt_add_sge(psge, flagsLength, dma_addr_in);
1400
1401 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
1402
1403 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
1404 if (!timeleft) {
1405 printk(KERN_ERR "%s: smp timeout!\n", __FUNCTION__);
1406 /* On timeout reset the board */
1407 mpt_HardResetHandler(ioc, CAN_SLEEP);
1408 ret = -ETIMEDOUT;
1409 goto unmap;
1410 }
1411 mf = NULL;
1412
1413 if (ioc->sas_mgmt.status & MPT_IOCTL_STATUS_RF_VALID) {
1414 SmpPassthroughReply_t *smprep;
1415
1416 smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
1417 memcpy(req->sense, smprep, sizeof(*smprep));
1418 req->sense_len = sizeof(*smprep);
1419 } else {
1420 printk(KERN_ERR "%s: smp passthru reply failed to be returned\n",
1421 __FUNCTION__);
1422 ret = -ENXIO;
1423 }
1424unmap:
1425 if (dma_addr_out)
1426 pci_unmap_single(ioc->pcidev, dma_addr_out, req->data_len,
1427 PCI_DMA_BIDIRECTIONAL);
1428 if (dma_addr_in)
1429 pci_unmap_single(ioc->pcidev, dma_addr_in, rsp->data_len,
1430 PCI_DMA_BIDIRECTIONAL);
1431put_mf:
1432 if (mf)
1433 mpt_free_msg_frame(ioc, mf);
1434out_unlock:
1435 mutex_unlock(&ioc->sas_mgmt.mutex);
1436out:
1437 return ret;
1438}
1439
1315static struct sas_function_template mptsas_transport_functions = { 1440static struct sas_function_template mptsas_transport_functions = {
1316 .get_linkerrors = mptsas_get_linkerrors, 1441 .get_linkerrors = mptsas_get_linkerrors,
1317 .get_enclosure_identifier = mptsas_get_enclosure_identifier, 1442 .get_enclosure_identifier = mptsas_get_enclosure_identifier,
1318 .get_bay_identifier = mptsas_get_bay_identifier, 1443 .get_bay_identifier = mptsas_get_bay_identifier,
1319 .phy_reset = mptsas_phy_reset, 1444 .phy_reset = mptsas_phy_reset,
1445 .smp_handler = mptsas_smp_handler,
1320}; 1446};
1321 1447
1322static struct scsi_transport_template *mptsas_transport_template; 1448static struct scsi_transport_template *mptsas_transport_template;