aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/message/fusion/mptfc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/message/fusion/mptfc.c')
-rw-r--r--drivers/message/fusion/mptfc.c149
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;
90module_param(max_lun, int, 0); 90module_param(max_lun, int, 0);
91MODULE_PARM_DESC(max_lun, " max lun, default=16895 "); 91MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
92 92
93static int mptfcDoneCtx = -1; 93static u8 mptfcDoneCtx = MPT_MAX_PROTOCOL_DRIVERS;
94static int mptfcTaskCtx = -1; 94static u8 mptfcTaskCtx = MPT_MAX_PROTOCOL_DRIVERS;
95static int mptfcInternalCtx = -1; /* Used only for internal commands */ 95static u8 mptfcInternalCtx = MPT_MAX_PROTOCOL_DRIVERS;
96 96
97static int mptfc_target_alloc(struct scsi_target *starget); 97static int mptfc_target_alloc(struct scsi_target *starget);
98static int mptfc_slave_alloc(struct scsi_device *sdev); 98static 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 */
684static void
685mptfc_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
1025static void 1070static void
1071mptfc_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
1082static void
1026mptfc_setup_reset(struct work_struct *work) 1083mptfc_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;