diff options
Diffstat (limited to 'drivers/message/fusion/mptfc.c')
-rw-r--r-- | drivers/message/fusion/mptfc.c | 149 |
1 files changed, 108 insertions, 41 deletions
diff --git a/drivers/message/fusion/mptfc.c b/drivers/message/fusion/mptfc.c index 8422c25e4a3e..3cdd4e962115 100644 --- a/drivers/message/fusion/mptfc.c +++ b/drivers/message/fusion/mptfc.c | |||
@@ -1,9 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * linux/drivers/message/fusion/mptfc.c | 2 | * linux/drivers/message/fusion/mptfc.c |
3 | * For use with LSI Logic PCI chip/adapter(s) | 3 | * For use with LSI PCI chip/adapter(s) |
4 | * running LSI Logic Fusion MPT (Message Passing Technology) firmware. | 4 | * running LSI Fusion MPT (Message Passing Technology) firmware. |
5 | * | 5 | * |
6 | * Copyright (c) 1999-2007 LSI Logic Corporation | 6 | * Copyright (c) 1999-2007 LSI Corporation |
7 | * (mailto:DL-MPTFusionLinux@lsi.com) | 7 | * (mailto:DL-MPTFusionLinux@lsi.com) |
8 | * | 8 | * |
9 | */ | 9 | */ |
@@ -90,9 +90,9 @@ static int max_lun = MPTFC_MAX_LUN; | |||
90 | module_param(max_lun, int, 0); | 90 | module_param(max_lun, int, 0); |
91 | MODULE_PARM_DESC(max_lun, " max lun, default=16895 "); | 91 | MODULE_PARM_DESC(max_lun, " max lun, default=16895 "); |
92 | 92 | ||
93 | static int mptfcDoneCtx = -1; | 93 | static u8 mptfcDoneCtx = MPT_MAX_PROTOCOL_DRIVERS; |
94 | static int mptfcTaskCtx = -1; | 94 | static u8 mptfcTaskCtx = MPT_MAX_PROTOCOL_DRIVERS; |
95 | static int mptfcInternalCtx = -1; /* Used only for internal commands */ | 95 | static u8 mptfcInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; |
96 | 96 | ||
97 | static int mptfc_target_alloc(struct scsi_target *starget); | 97 | static int mptfc_target_alloc(struct scsi_target *starget); |
98 | static int mptfc_slave_alloc(struct scsi_device *sdev); | 98 | static int mptfc_slave_alloc(struct scsi_device *sdev); |
@@ -194,37 +194,36 @@ mptfc_block_error_handler(struct scsi_cmnd *SCpnt, | |||
194 | struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); | 194 | struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); |
195 | unsigned long flags; | 195 | unsigned long flags; |
196 | int ready; | 196 | int ready; |
197 | MPT_ADAPTER *ioc; | ||
197 | 198 | ||
198 | hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata; | 199 | hd = shost_priv(SCpnt->device->host); |
200 | ioc = hd->ioc; | ||
199 | spin_lock_irqsave(shost->host_lock, flags); | 201 | spin_lock_irqsave(shost->host_lock, flags); |
200 | while ((ready = fc_remote_port_chkready(rport) >> 16) == DID_IMM_RETRY) { | 202 | while ((ready = fc_remote_port_chkready(rport) >> 16) == DID_IMM_RETRY) { |
201 | spin_unlock_irqrestore(shost->host_lock, flags); | 203 | spin_unlock_irqrestore(shost->host_lock, flags); |
202 | dfcprintk (hd->ioc, printk(MYIOC_s_DEBUG_FMT | 204 | dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT |
203 | "mptfc_block_error_handler.%d: %d:%d, port status is " | 205 | "mptfc_block_error_handler.%d: %d:%d, port status is " |
204 | "DID_IMM_RETRY, deferring %s recovery.\n", | 206 | "DID_IMM_RETRY, deferring %s recovery.\n", |
205 | ((MPT_SCSI_HOST *) shost->hostdata)->ioc->name, | 207 | ioc->name, ioc->sh->host_no, |
206 | ((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no, | 208 | SCpnt->device->id, SCpnt->device->lun, caller)); |
207 | SCpnt->device->id,SCpnt->device->lun,caller)); | ||
208 | msleep(1000); | 209 | msleep(1000); |
209 | spin_lock_irqsave(shost->host_lock, flags); | 210 | spin_lock_irqsave(shost->host_lock, flags); |
210 | } | 211 | } |
211 | spin_unlock_irqrestore(shost->host_lock, flags); | 212 | spin_unlock_irqrestore(shost->host_lock, flags); |
212 | 213 | ||
213 | if (ready == DID_NO_CONNECT || !SCpnt->device->hostdata) { | 214 | if (ready == DID_NO_CONNECT || !SCpnt->device->hostdata) { |
214 | dfcprintk (hd->ioc, printk(MYIOC_s_DEBUG_FMT | 215 | dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT |
215 | "%s.%d: %d:%d, failing recovery, " | 216 | "%s.%d: %d:%d, failing recovery, " |
216 | "port state %d, vdev %p.\n", caller, | 217 | "port state %d, vdevice %p.\n", caller, |
217 | ((MPT_SCSI_HOST *) shost->hostdata)->ioc->name, | 218 | ioc->name, ioc->sh->host_no, |
218 | ((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no, | 219 | SCpnt->device->id, SCpnt->device->lun, ready, |
219 | SCpnt->device->id,SCpnt->device->lun,ready, | ||
220 | SCpnt->device->hostdata)); | 220 | SCpnt->device->hostdata)); |
221 | return FAILED; | 221 | return FAILED; |
222 | } | 222 | } |
223 | dfcprintk (hd->ioc, printk(MYIOC_s_DEBUG_FMT | 223 | dfcprintk (ioc, printk(MYIOC_s_DEBUG_FMT |
224 | "%s.%d: %d:%d, executing recovery.\n", caller, | 224 | "%s.%d: %d:%d, executing recovery.\n", caller, |
225 | ((MPT_SCSI_HOST *) shost->hostdata)->ioc->name, | 225 | ioc->name, ioc->sh->host_no, |
226 | ((MPT_SCSI_HOST *) shost->hostdata)->ioc->sh->host_no, | 226 | SCpnt->device->id, SCpnt->device->lun)); |
227 | SCpnt->device->id,SCpnt->device->lun)); | ||
228 | return (*func)(SCpnt); | 227 | return (*func)(SCpnt); |
229 | } | 228 | } |
230 | 229 | ||
@@ -470,7 +469,7 @@ mptfc_register_dev(MPT_ADAPTER *ioc, int channel, FCDevicePage0_t *pg0) | |||
470 | /* | 469 | /* |
471 | * if already mapped, remap here. If not mapped, | 470 | * if already mapped, remap here. If not mapped, |
472 | * target_alloc will allocate vtarget and map, | 471 | * target_alloc will allocate vtarget and map, |
473 | * slave_alloc will fill in vdev from vtarget. | 472 | * slave_alloc will fill in vdevice from vtarget. |
474 | */ | 473 | */ |
475 | if (ri->starget) { | 474 | if (ri->starget) { |
476 | vtarget = ri->starget->hostdata; | 475 | vtarget = ri->starget->hostdata; |
@@ -602,10 +601,10 @@ mptfc_slave_alloc(struct scsi_device *sdev) | |||
602 | { | 601 | { |
603 | MPT_SCSI_HOST *hd; | 602 | MPT_SCSI_HOST *hd; |
604 | VirtTarget *vtarget; | 603 | VirtTarget *vtarget; |
605 | VirtDevice *vdev; | 604 | VirtDevice *vdevice; |
606 | struct scsi_target *starget; | 605 | struct scsi_target *starget; |
607 | struct fc_rport *rport; | 606 | struct fc_rport *rport; |
608 | 607 | MPT_ADAPTER *ioc; | |
609 | 608 | ||
610 | starget = scsi_target(sdev); | 609 | starget = scsi_target(sdev); |
611 | rport = starget_to_rport(starget); | 610 | rport = starget_to_rport(starget); |
@@ -613,31 +612,32 @@ mptfc_slave_alloc(struct scsi_device *sdev) | |||
613 | if (!rport || fc_remote_port_chkready(rport)) | 612 | if (!rport || fc_remote_port_chkready(rport)) |
614 | return -ENXIO; | 613 | return -ENXIO; |
615 | 614 | ||
616 | hd = (MPT_SCSI_HOST *)sdev->host->hostdata; | 615 | hd = shost_priv(sdev->host); |
616 | ioc = hd->ioc; | ||
617 | 617 | ||
618 | vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL); | 618 | vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL); |
619 | if (!vdev) { | 619 | if (!vdevice) { |
620 | printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n", | 620 | printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n", |
621 | hd->ioc->name, sizeof(VirtDevice)); | 621 | ioc->name, sizeof(VirtDevice)); |
622 | return -ENOMEM; | 622 | return -ENOMEM; |
623 | } | 623 | } |
624 | 624 | ||
625 | 625 | ||
626 | sdev->hostdata = vdev; | 626 | sdev->hostdata = vdevice; |
627 | vtarget = starget->hostdata; | 627 | vtarget = starget->hostdata; |
628 | 628 | ||
629 | if (vtarget->num_luns == 0) { | 629 | if (vtarget->num_luns == 0) { |
630 | vtarget->ioc_id = hd->ioc->id; | 630 | vtarget->ioc_id = ioc->id; |
631 | vtarget->tflags = MPT_TARGET_FLAGS_Q_YES; | 631 | vtarget->tflags = MPT_TARGET_FLAGS_Q_YES; |
632 | } | 632 | } |
633 | 633 | ||
634 | vdev->vtarget = vtarget; | 634 | vdevice->vtarget = vtarget; |
635 | vdev->lun = sdev->lun; | 635 | vdevice->lun = sdev->lun; |
636 | 636 | ||
637 | vtarget->num_luns++; | 637 | vtarget->num_luns++; |
638 | 638 | ||
639 | 639 | ||
640 | mptfc_dump_lun_info(hd->ioc, rport, sdev, vtarget); | 640 | mptfc_dump_lun_info(ioc, rport, sdev, vtarget); |
641 | 641 | ||
642 | return 0; | 642 | return 0; |
643 | } | 643 | } |
@@ -648,9 +648,9 @@ mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) | |||
648 | struct mptfc_rport_info *ri; | 648 | struct mptfc_rport_info *ri; |
649 | struct fc_rport *rport = starget_to_rport(scsi_target(SCpnt->device)); | 649 | struct fc_rport *rport = starget_to_rport(scsi_target(SCpnt->device)); |
650 | int err; | 650 | int err; |
651 | VirtDevice *vdev = SCpnt->device->hostdata; | 651 | VirtDevice *vdevice = SCpnt->device->hostdata; |
652 | 652 | ||
653 | if (!vdev || !vdev->vtarget) { | 653 | if (!vdevice || !vdevice->vtarget) { |
654 | SCpnt->result = DID_NO_CONNECT << 16; | 654 | SCpnt->result = DID_NO_CONNECT << 16; |
655 | done(SCpnt); | 655 | done(SCpnt); |
656 | return 0; | 656 | return 0; |
@@ -675,6 +675,50 @@ mptfc_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) | |||
675 | } | 675 | } |
676 | 676 | ||
677 | /* | 677 | /* |
678 | * mptfc_display_port_link_speed - displaying link speed | ||
679 | * @ioc: Pointer to MPT_ADAPTER structure | ||
680 | * @portnum: IOC Port number | ||
681 | * @pp0dest: port page0 data payload | ||
682 | * | ||
683 | */ | ||
684 | static void | ||
685 | mptfc_display_port_link_speed(MPT_ADAPTER *ioc, int portnum, FCPortPage0_t *pp0dest) | ||
686 | { | ||
687 | u8 old_speed, new_speed, state; | ||
688 | char *old, *new; | ||
689 | |||
690 | if (portnum >= 2) | ||
691 | return; | ||
692 | |||
693 | old_speed = ioc->fc_link_speed[portnum]; | ||
694 | new_speed = pp0dest->CurrentSpeed; | ||
695 | state = pp0dest->PortState; | ||
696 | |||
697 | if (state != MPI_FCPORTPAGE0_PORTSTATE_OFFLINE && | ||
698 | new_speed != MPI_FCPORTPAGE0_CURRENT_SPEED_UKNOWN) { | ||
699 | |||
700 | old = old_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_1GBIT ? "1 Gbps" : | ||
701 | old_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_2GBIT ? "2 Gbps" : | ||
702 | old_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_4GBIT ? "4 Gbps" : | ||
703 | "Unknown"; | ||
704 | new = new_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_1GBIT ? "1 Gbps" : | ||
705 | new_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_2GBIT ? "2 Gbps" : | ||
706 | new_speed == MPI_FCPORTPAGE0_CURRENT_SPEED_4GBIT ? "4 Gbps" : | ||
707 | "Unknown"; | ||
708 | if (old_speed == 0) | ||
709 | printk(MYIOC_s_NOTE_FMT | ||
710 | "FC Link Established, Speed = %s\n", | ||
711 | ioc->name, new); | ||
712 | else if (old_speed != new_speed) | ||
713 | printk(MYIOC_s_WARN_FMT | ||
714 | "FC Link Speed Change, Old Speed = %s, New Speed = %s\n", | ||
715 | ioc->name, old, new); | ||
716 | |||
717 | ioc->fc_link_speed[portnum] = new_speed; | ||
718 | } | ||
719 | } | ||
720 | |||
721 | /* | ||
678 | * mptfc_GetFcPortPage0 - Fetch FCPort config Page0. | 722 | * mptfc_GetFcPortPage0 - Fetch FCPort config Page0. |
679 | * @ioc: Pointer to MPT_ADAPTER structure | 723 | * @ioc: Pointer to MPT_ADAPTER structure |
680 | * @portnum: IOC Port number | 724 | * @portnum: IOC Port number |
@@ -773,6 +817,7 @@ mptfc_GetFcPortPage0(MPT_ADAPTER *ioc, int portnum) | |||
773 | " complete.\n", | 817 | " complete.\n", |
774 | ioc->name); | 818 | ioc->name); |
775 | } | 819 | } |
820 | mptfc_display_port_link_speed(ioc, portnum, pp0dest); | ||
776 | } | 821 | } |
777 | 822 | ||
778 | pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma); | 823 | pci_free_consistent(ioc->pcidev, data_sz, (u8 *) ppage0_alloc, page0_dma); |
@@ -1023,6 +1068,18 @@ mptfc_init_host_attr(MPT_ADAPTER *ioc,int portnum) | |||
1023 | } | 1068 | } |
1024 | 1069 | ||
1025 | static void | 1070 | static void |
1071 | mptfc_link_status_change(struct work_struct *work) | ||
1072 | { | ||
1073 | MPT_ADAPTER *ioc = | ||
1074 | container_of(work, MPT_ADAPTER, fc_rescan_work); | ||
1075 | int ii; | ||
1076 | |||
1077 | for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) | ||
1078 | (void) mptfc_GetFcPortPage0(ioc, ii); | ||
1079 | |||
1080 | } | ||
1081 | |||
1082 | static void | ||
1026 | mptfc_setup_reset(struct work_struct *work) | 1083 | mptfc_setup_reset(struct work_struct *work) |
1027 | { | 1084 | { |
1028 | MPT_ADAPTER *ioc = | 1085 | MPT_ADAPTER *ioc = |
@@ -1163,6 +1220,7 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
1163 | spin_lock_init(&ioc->fc_rescan_work_lock); | 1220 | spin_lock_init(&ioc->fc_rescan_work_lock); |
1164 | INIT_WORK(&ioc->fc_rescan_work, mptfc_rescan_devices); | 1221 | INIT_WORK(&ioc->fc_rescan_work, mptfc_rescan_devices); |
1165 | INIT_WORK(&ioc->fc_setup_reset_work, mptfc_setup_reset); | 1222 | INIT_WORK(&ioc->fc_setup_reset_work, mptfc_setup_reset); |
1223 | INIT_WORK(&ioc->fc_lsc_work, mptfc_link_status_change); | ||
1166 | 1224 | ||
1167 | spin_lock_irqsave(&ioc->FreeQlock, flags); | 1225 | spin_lock_irqsave(&ioc->FreeQlock, flags); |
1168 | 1226 | ||
@@ -1218,20 +1276,21 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
1218 | 1276 | ||
1219 | spin_unlock_irqrestore(&ioc->FreeQlock, flags); | 1277 | spin_unlock_irqrestore(&ioc->FreeQlock, flags); |
1220 | 1278 | ||
1221 | hd = (MPT_SCSI_HOST *) sh->hostdata; | 1279 | hd = shost_priv(sh); |
1222 | hd->ioc = ioc; | 1280 | hd->ioc = ioc; |
1223 | 1281 | ||
1224 | /* SCSI needs scsi_cmnd lookup table! | 1282 | /* SCSI needs scsi_cmnd lookup table! |
1225 | * (with size equal to req_depth*PtrSz!) | 1283 | * (with size equal to req_depth*PtrSz!) |
1226 | */ | 1284 | */ |
1227 | hd->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC); | 1285 | ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC); |
1228 | if (!hd->ScsiLookup) { | 1286 | if (!ioc->ScsiLookup) { |
1229 | error = -ENOMEM; | 1287 | error = -ENOMEM; |
1230 | goto out_mptfc_probe; | 1288 | goto out_mptfc_probe; |
1231 | } | 1289 | } |
1290 | spin_lock_init(&ioc->scsi_lookup_lock); | ||
1232 | 1291 | ||
1233 | dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n", | 1292 | dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n", |
1234 | ioc->name, hd->ScsiLookup)); | 1293 | ioc->name, ioc->ScsiLookup)); |
1235 | 1294 | ||
1236 | /* Clear the TM flags | 1295 | /* Clear the TM flags |
1237 | */ | 1296 | */ |
@@ -1262,8 +1321,8 @@ mptfc_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
1262 | sh->transportt = mptfc_transport_template; | 1321 | sh->transportt = mptfc_transport_template; |
1263 | error = scsi_add_host (sh, &ioc->pcidev->dev); | 1322 | error = scsi_add_host (sh, &ioc->pcidev->dev); |
1264 | if(error) { | 1323 | if(error) { |
1265 | dprintk(ioc, printk(KERN_ERR MYNAM | 1324 | dprintk(ioc, printk(MYIOC_s_ERR_FMT |
1266 | "scsi_add_host failed\n")); | 1325 | "scsi_add_host failed\n", ioc->name)); |
1267 | goto out_mptfc_probe; | 1326 | goto out_mptfc_probe; |
1268 | } | 1327 | } |
1269 | 1328 | ||
@@ -1325,7 +1384,7 @@ mptfc_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) | |||
1325 | ioc->name, event)); | 1384 | ioc->name, event)); |
1326 | 1385 | ||
1327 | if (ioc->sh == NULL || | 1386 | if (ioc->sh == NULL || |
1328 | ((hd = (MPT_SCSI_HOST *)ioc->sh->hostdata) == NULL)) | 1387 | ((hd = shost_priv(ioc->sh)) == NULL)) |
1329 | return 1; | 1388 | return 1; |
1330 | 1389 | ||
1331 | switch (event) { | 1390 | switch (event) { |
@@ -1337,6 +1396,14 @@ mptfc_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply) | |||
1337 | } | 1396 | } |
1338 | spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags); | 1397 | spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags); |
1339 | break; | 1398 | break; |
1399 | case MPI_EVENT_LINK_STATUS_CHANGE: | ||
1400 | spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags); | ||
1401 | if (ioc->fc_rescan_work_q) { | ||
1402 | queue_work(ioc->fc_rescan_work_q, | ||
1403 | &ioc->fc_lsc_work); | ||
1404 | } | ||
1405 | spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags); | ||
1406 | break; | ||
1340 | default: | 1407 | default: |
1341 | rc = mptscsih_event_process(ioc,pEvReply); | 1408 | rc = mptscsih_event_process(ioc,pEvReply); |
1342 | break; | 1409 | break; |