diff options
author | Christoph Hellwig <hch@lst.de> | 2005-10-19 14:01:42 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.(none)> | 2005-10-28 20:09:31 -0400 |
commit | da4fa65596733914b3c21fdffa02593959c67f56 (patch) | |
tree | 6a918d3feb6fe266e90dd4634775ae749bade6d0 | |
parent | 07ba3a954714da10cbd3f6249d93ac2c1df72c4f (diff) |
[SCSI] mptsas: add support for PHY resets
Support PHY resets in mptsas. Thanks to Eric for various bug fixes
and improvements.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
-rw-r--r-- | drivers/message/fusion/mptbase.h | 12 | ||||
-rw-r--r-- | drivers/message/fusion/mptsas.c | 88 |
2 files changed, 100 insertions, 0 deletions
diff --git a/drivers/message/fusion/mptbase.h b/drivers/message/fusion/mptbase.h index 75105277e22f..e705272bc37a 100644 --- a/drivers/message/fusion/mptbase.h +++ b/drivers/message/fusion/mptbase.h | |||
@@ -421,6 +421,17 @@ typedef struct _MPT_IOCTL { | |||
421 | struct semaphore sem_ioc; | 421 | struct semaphore sem_ioc; |
422 | } MPT_IOCTL; | 422 | } MPT_IOCTL; |
423 | 423 | ||
424 | #define MPT_SAS_MGMT_STATUS_RF_VALID 0x02 /* The Reply Frame is VALID */ | ||
425 | #define MPT_SAS_MGMT_STATUS_COMMAND_GOOD 0x10 /* Command Status GOOD */ | ||
426 | #define MPT_SAS_MGMT_STATUS_TM_FAILED 0x40 /* User TM request failed */ | ||
427 | |||
428 | typedef struct _MPT_SAS_MGMT { | ||
429 | struct semaphore mutex; | ||
430 | struct completion done; | ||
431 | u8 reply[MPT_DEFAULT_FRAME_SIZE]; /* reply frame data */ | ||
432 | u8 status; /* current command status */ | ||
433 | }MPT_SAS_MGMT; | ||
434 | |||
424 | /* | 435 | /* |
425 | * Event Structure and define | 436 | * Event Structure and define |
426 | */ | 437 | */ |
@@ -604,6 +615,7 @@ typedef struct _MPT_ADAPTER | |||
604 | struct list_head list; | 615 | struct list_head list; |
605 | struct net_device *netdev; | 616 | struct net_device *netdev; |
606 | struct list_head sas_topology; | 617 | struct list_head sas_topology; |
618 | MPT_SAS_MGMT sas_mgmt; | ||
607 | } MPT_ADAPTER; | 619 | } MPT_ADAPTER; |
608 | 620 | ||
609 | /* | 621 | /* |
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c index dcdf0380be86..1c557a09b916 100644 --- a/drivers/message/fusion/mptsas.c +++ b/drivers/message/fusion/mptsas.c | |||
@@ -83,6 +83,7 @@ MODULE_PARM_DESC(mpt_pt_clear, | |||
83 | static int mptsasDoneCtx = -1; | 83 | static int mptsasDoneCtx = -1; |
84 | static int mptsasTaskCtx = -1; | 84 | static int mptsasTaskCtx = -1; |
85 | static int mptsasInternalCtx = -1; /* Used only for internal commands */ | 85 | static int mptsasInternalCtx = -1; /* Used only for internal commands */ |
86 | static int mptsasMgmtCtx = -1; | ||
86 | 87 | ||
87 | 88 | ||
88 | /* | 89 | /* |
@@ -359,9 +360,92 @@ static int mptsas_get_linkerrors(struct sas_phy *phy) | |||
359 | return error; | 360 | return error; |
360 | } | 361 | } |
361 | 362 | ||
363 | static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req, | ||
364 | MPT_FRAME_HDR *reply) | ||
365 | { | ||
366 | ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_COMMAND_GOOD; | ||
367 | if (reply != NULL) { | ||
368 | ioc->sas_mgmt.status |= MPT_SAS_MGMT_STATUS_RF_VALID; | ||
369 | memcpy(ioc->sas_mgmt.reply, reply, | ||
370 | min(ioc->reply_sz, 4 * reply->u.reply.MsgLength)); | ||
371 | } | ||
372 | complete(&ioc->sas_mgmt.done); | ||
373 | return 1; | ||
374 | } | ||
375 | |||
376 | static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset) | ||
377 | { | ||
378 | MPT_ADAPTER *ioc = phy_to_ioc(phy); | ||
379 | SasIoUnitControlRequest_t *req; | ||
380 | SasIoUnitControlReply_t *reply; | ||
381 | MPT_FRAME_HDR *mf; | ||
382 | MPIHeader_t *hdr; | ||
383 | unsigned long timeleft; | ||
384 | int error = -ERESTARTSYS; | ||
385 | |||
386 | /* not implemented for expanders */ | ||
387 | if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP) | ||
388 | return -ENXIO; | ||
389 | |||
390 | if (down_interruptible(&ioc->sas_mgmt.mutex)) | ||
391 | goto out; | ||
392 | |||
393 | mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc); | ||
394 | if (!mf) { | ||
395 | error = -ENOMEM; | ||
396 | goto out_unlock; | ||
397 | } | ||
398 | |||
399 | hdr = (MPIHeader_t *) mf; | ||
400 | req = (SasIoUnitControlRequest_t *)mf; | ||
401 | memset(req, 0, sizeof(SasIoUnitControlRequest_t)); | ||
402 | req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL; | ||
403 | req->MsgContext = hdr->MsgContext; | ||
404 | req->Operation = hard_reset ? | ||
405 | MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET; | ||
406 | req->PhyNum = phy->identify.phy_identifier; | ||
407 | |||
408 | mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf); | ||
409 | |||
410 | timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, | ||
411 | 10 * HZ); | ||
412 | if (!timeleft) { | ||
413 | /* On timeout reset the board */ | ||
414 | mpt_free_msg_frame(ioc, mf); | ||
415 | mpt_HardResetHandler(ioc, CAN_SLEEP); | ||
416 | error = -ETIMEDOUT; | ||
417 | goto out_unlock; | ||
418 | } | ||
419 | |||
420 | /* a reply frame is expected */ | ||
421 | if ((ioc->sas_mgmt.status & | ||
422 | MPT_IOCTL_STATUS_RF_VALID) == 0) { | ||
423 | error = -ENXIO; | ||
424 | goto out_unlock; | ||
425 | } | ||
426 | |||
427 | /* process the completed Reply Message Frame */ | ||
428 | reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply; | ||
429 | if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) { | ||
430 | printk("%s: IOCStatus=0x%X IOCLogInfo=0x%X\n", | ||
431 | __FUNCTION__, | ||
432 | reply->IOCStatus, | ||
433 | reply->IOCLogInfo); | ||
434 | error = -ENXIO; | ||
435 | goto out_unlock; | ||
436 | } | ||
437 | |||
438 | error = 0; | ||
439 | |||
440 | out_unlock: | ||
441 | up(&ioc->sas_mgmt.mutex); | ||
442 | out: | ||
443 | return error; | ||
444 | } | ||
362 | 445 | ||
363 | static struct sas_function_template mptsas_transport_functions = { | 446 | static struct sas_function_template mptsas_transport_functions = { |
364 | .get_linkerrors = mptsas_get_linkerrors, | 447 | .get_linkerrors = mptsas_get_linkerrors, |
448 | .phy_reset = mptsas_phy_reset, | ||
365 | }; | 449 | }; |
366 | 450 | ||
367 | static struct scsi_transport_template *mptsas_transport_template; | 451 | static struct scsi_transport_template *mptsas_transport_template; |
@@ -1105,6 +1189,8 @@ mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
1105 | sh->unique_id = ioc->id; | 1189 | sh->unique_id = ioc->id; |
1106 | 1190 | ||
1107 | INIT_LIST_HEAD(&ioc->sas_topology); | 1191 | INIT_LIST_HEAD(&ioc->sas_topology); |
1192 | init_MUTEX(&ioc->sas_mgmt.mutex); | ||
1193 | init_completion(&ioc->sas_mgmt.done); | ||
1108 | 1194 | ||
1109 | /* Verify that we won't exceed the maximum | 1195 | /* Verify that we won't exceed the maximum |
1110 | * number of chain buffers | 1196 | * number of chain buffers |
@@ -1291,6 +1377,7 @@ mptsas_init(void) | |||
1291 | mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER); | 1377 | mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER); |
1292 | mptsasInternalCtx = | 1378 | mptsasInternalCtx = |
1293 | mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER); | 1379 | mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER); |
1380 | mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER); | ||
1294 | 1381 | ||
1295 | if (mpt_event_register(mptsasDoneCtx, mptscsih_event_process) == 0) { | 1382 | if (mpt_event_register(mptsasDoneCtx, mptscsih_event_process) == 0) { |
1296 | devtprintk((KERN_INFO MYNAM | 1383 | devtprintk((KERN_INFO MYNAM |
@@ -1314,6 +1401,7 @@ mptsas_exit(void) | |||
1314 | mpt_reset_deregister(mptsasDoneCtx); | 1401 | mpt_reset_deregister(mptsasDoneCtx); |
1315 | mpt_event_deregister(mptsasDoneCtx); | 1402 | mpt_event_deregister(mptsasDoneCtx); |
1316 | 1403 | ||
1404 | mpt_deregister(mptsasMgmtCtx); | ||
1317 | mpt_deregister(mptsasInternalCtx); | 1405 | mpt_deregister(mptsasInternalCtx); |
1318 | mpt_deregister(mptsasTaskCtx); | 1406 | mpt_deregister(mptsasTaskCtx); |
1319 | mpt_deregister(mptsasDoneCtx); | 1407 | mpt_deregister(mptsasDoneCtx); |